Lock 锁
803字约3分钟
2024-08-08
synchronized
卖票问题
public static void main(String[] args) {
// 并发:多线程操作同一个资源类,把资源类丢入线程
Ticket ticket = new Ticket();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "C").start();
}
// 不去继承 Thread 或实现 runabble,实现解耦
class Ticket {
private int num = 30;
public synchronized void sale() {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "卖出编号为 " + (num--) + " 的票,剩余 " + num + " 张");
}
}
}
lock 接口
所有已知实现类
ReentrantLock
:可重入锁(常用)ReentrantReadWriteLock.ReadLock
:读锁ReentrantReadWriteLock.WriteLock
:写锁
虽然 synchronized
方法和语句的范围机制使得使用监视器锁更容易编程,并且有助于避免涉及锁的许多常见编程错误,但是有时您需要以更灵活的方式处理锁。 例如,用于遍历并发访问的数据结构的一些算法需要使用“手动”或“链锁定”:您获取节点 A
的锁定,然后获取节点 B
,然后释放A并获取 C
,然后释放 B
并获得 D
等。 所述的实施方式中 Lock
接口通过允许获得并在不同的范围释放的锁,并允许获得并以任何顺序释放多个锁使得能够使用这样的技术
随着这种增加的灵活性,额外的责任。 没有块结构化锁定会删除使用 synchronized
方法和语句发生的锁的自动释放。 在大多数情况下,应使用以下惯用语:
Lock l = ...; l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
ReentrantLock
公平锁:十分公平,先来后到
非公平锁:十分不公平,可以插队(默认)
/**
* ReentrantLock 类,默认创建非公平锁
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* 创建传入 true,则创建公平锁
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
卖票问题
lock 使用
1、
new ReentrantLock();
2、
lock.lock();
加锁3、
finally 中 lock.unlock();
释放锁
public static void main(String[] args) {
// 并发:多线程操作同一个资源类,把资源类丢入线程
Ticket2 ticket = new Ticket2();
new Thread(() -> { for (int i = 0; i < 40; i++) ticket.sale();}, "A").start();
new Thread(() -> { for (int i = 0; i < 40; i++) ticket.sale();}, "B").start();
new Thread(() -> { for (int i = 0; i < 40; i++) ticket.sale();}, "C").start();
}
class Ticket2 {
private int num = 30;
Lock lock = new ReentrantLock();
public void sale() {
// 加锁
lock.lock();
try {
// 业务代码
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "卖出编号为 " + (num--) + " 的票,剩余 " + num + " 张");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 解锁
lock.unlock();
}
}
}
Synchronized
和 Lock
区别
Synchronized
内置的java
关键字;Lock
是一个java
类Synchronized
无法判断获取锁的状态;Lock
可以判断是否获取到了锁Synchronized
会自动释放锁;Lock
必须手动释放锁,如果不释放会造成死锁Synchronized
线程1(获得锁,阻塞),线程2
(等待,傻傻的等);Lock
锁就不一定会等待下去(lock.tryLock()
)Synchronized
可重入锁,不可以中断的,非公平;Lock
可重入锁,非公平(可自己设置)Synchronized
适合锁少量的代码同步问题;Lock
适合锁大量的同步代码