[JUC笔记]2.LOCK
多线程编程步骤
- 创建资源类,在资源类创建属性和操作方法【也就是run方法】
- 什么是资源类?
- 类似于空调,每个人都可以买,每个人都可以控制空调的各个功能
- 高内聚低耦合
- 什么是资源类?
- 创建多个线程,调用资源类的操作方法
覆写run的目的:将自定义代码存储在run方法,让线程运行。
start方法:调用线程并执行该线程run方法
创建线程的多种方式:
- 继承Thread类 【Java是单继承,因此很少用这种方式】
- 实现Runnable接口
Thread(Runnable target,String name)
- 使用Callable接口
- 使用线程池
卖票举例代码
package sync;
import java.sql.Timestamp;
// 第一步: 创建资源类,定义属性和操作方法
class Ticket
{
// 属性:票数
private int number = 30;
/**
* 操作方法:买票
* 但是因为是多线程操作,因此需要添加关键字: synchronized
*/
public synchronized void sale()
{
if (number > 0)
{
System.out.println(Thread.currentThread().getName() + "卖出:" + (number--) + " 剩下:" + number);
}
}
}
public class SaleTicket
{
// 第二部:创建多个线程,调用资源类的操作方法
public static void main(String[] args)
{
// 创建ticket对象
Ticket ticket = new Ticket();
// 创建三个线程,采用匿名内部类的方式
new Thread(new Runnable()
{
@Override
public void run()
{
// 调用买票的方法
for(int i=0;i<40;i++)
{
ticket.sale();
}
}
},"AA").start();
// 第二个线程
new Thread(new Runnable()
{
@Override
public void run()
{
// 调用买票的方法
for(int i=0;i<40;i++)
{
ticket.sale();
}
}
},"BB").start();
// 第三个线程
new Thread(new Runnable()
{
@Override
public void run()
{
// 调用买票的方法
for(int i=0;i<40;i++)
{
ticket.sale();
}
}
},"CC").start();
}
}
AA卖出:30 剩下:29
AA卖出:29 剩下:28
AA卖出:28 剩下:27
AA卖出:27 剩下:26
AA卖出:26 剩下:25
AA卖出:25 剩下:24
AA卖出:24 剩下:23
AA卖出:23 剩下:22
AA卖出:22 剩下:21
AA卖出:21 剩下:20
AA卖出:20 剩下:19
AA卖出:19 剩下:18
AA卖出:18 剩下:17
AA卖出:17 剩下:16
AA卖出:16 剩下:15
AA卖出:15 剩下:14
AA卖出:14 剩下:13
AA卖出:13 剩下:12
AA卖出:12 剩下:11
AA卖出:11 剩下:10
BB卖出:10 剩下:9
BB卖出:9 剩下:8
BB卖出:8 剩下:7
BB卖出:7 剩下:6
BB卖出:6 剩下:5
BB卖出:5 剩下:4
BB卖出:4 剩下:3
BB卖出:3 剩下:2
BB卖出:2 剩下:1
BB卖出:1 剩下:0
Process finished with exit code 0
LOCK接口
synchronized是自动上锁、解锁 , 而LOCK接口能够手动实现上锁。
java.util.concurrent.locks
实现类
- ReentrantLock: 可重入锁
- ReentrantReadWriteLock.ReadLock
- ReentrantReadWriteLock.WriteLock
可重入锁举例: 上厕所,你进去把厕所门上锁,你出来了在把门解锁,下一个人进去了上锁,出来的时候解锁。就是这样的。
package Lock;
import java.util.concurrent.locks.ReentrantLock;
// 创建资源类,定义属性和操作方法
class Lticket
{
// 票数量
private int number = 30;
// 创建可重入锁
private final ReentrantLock lock = new ReentrantLock();
// 买票方法
public void sale()
{
// 上锁
lock.lock();
// 判断是否有票可卖
/*if (number > 0)
{
System.out.println(Thread.currentThread().getName() + ":卖出了" + number-- + " s");
}
// 解锁
lock.unlock();*/
/*上面这么写有可能出现一个问题,上锁之后,if判断语句里面出异常了,就会无法释放锁,造成死锁了
* 因此,采用try_catch */
try
{
// 判断有票可卖
if(number>0)
{
System.out.println(Thread.currentThread().getName() + ": 卖出" + (number--) + "剩余: " + number);
}
}
finally
{
lock.unlock();
}
}
}
public class LSaleTicket
{
// 第二步:创建多个线程,调用资源类的属性与方法
public static void main(String[] args)
{
Lticket ticket = new Lticket();
// 创建线程,采用Lambda 方式
new Thread(()->
{
for (int i=0;i<40;i++)
{
ticket.sale();
}
},"AA").start();
new Thread(()->
{
for (int i=0;i<40;i++)
{
ticket.sale();
}
},"BB").start();
new Thread(()->
{
for (int i=0;i<40;i++)
{
ticket.sale();
}
},"CC").start();
}
}
AA: 卖出30剩余: 29
AA: 卖出29剩余: 28
AA: 卖出28剩余: 27
AA: 卖出27剩余: 26
AA: 卖出26剩余: 25
AA: 卖出25剩余: 24
AA: 卖出24剩余: 23
CC: 卖出23剩余: 22
CC: 卖出22剩余: 21
CC: 卖出21剩余: 20
CC: 卖出20剩余: 19
CC: 卖出19剩余: 18
CC: 卖出18剩余: 17
CC: 卖出17剩余: 16
CC: 卖出16剩余: 15
CC: 卖出15剩余: 14
CC: 卖出14剩余: 13
CC: 卖出13剩余: 12
CC: 卖出12剩余: 11
CC: 卖出11剩余: 10
CC: 卖出10剩余: 9
CC: 卖出9剩余: 8
CC: 卖出8剩余: 7
CC: 卖出7剩余: 6
CC: 卖出6剩余: 5
CC: 卖出5剩余: 4
CC: 卖出4剩余: 3
CC: 卖出3剩余: 2
CC: 卖出2剩余: 1
CC: 卖出1剩余: 0
Process finished with exit code 0
LOCK与synchronized 的区别
- Lock不是Java语言内置的,synchronize是Java语言的关键字,是内置的。Lock是一个类,通过这个类可以实现同步访问。
- 采用Synchronized不需要用户手动释放锁。当synchronized方法或者代码块执行结束之后,系统会自动让线程释放锁。
- 而Lock必须手动释放锁,如果没有手动主动释放锁,就有可能出现死锁的现象。
- Lock 可以让等待锁的线程响应中断,
- 而 synchronized 却不行,使用synchronized 时,等待的线程会一直等待下去,不能够响应中断;
- 通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到。
- Lock 可以提高多个线程进行读操作的效率。

浙公网安备 33010602011771号