Lock 有别于 synchronized 隐式锁的三个特征:能够响应中断。支持超时和非阻塞地获取锁,也就是说 lock 比 synchronized 的功能丰富。
JavaSDK 并发包通过 Lock 和 Condition 两个接 口来实现管程,其中 Lock 用于解决互斥问题,Condition 用于解决同步问题。
Lock 接口的三个方法:
// ⽀持中断的 API
void lockInterruptibly() throws InterruptedException;
// ⽀持超时的 API
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// ⽀持⾮阻塞获取锁的 API
boolean tryLock();
如何保证可见性
class X {private final Lock rtl = new ReentrantLock();
int value;
public void addOne() {
// 获取锁
rtl.lock();
try {value+=1;} finally {
// 保证锁能释放
rtl.unlock();}
}
}
什么是可重入锁(ReentrantLock)
指线程可以重复获取同一把锁。
// ⽆参构造函数:默认⾮公平锁
public ReentrantLock() {sync = new NonfairSync();
}
// 根据公平策略参数创建锁 fair=true 是公平锁
public ReentrantLock(boolean fair){sync = fair ? new FairSync() : new NonfairSync();}
非公平可重入锁示例:
线程可以重复获取同一把锁。
/**
* 当线程 t 执行到①处时, 已经获取到了锁 rtl,* 当在①处调用 get() 方法时,会在②再次对锁 rtl 执行加锁操作。* 此时,如果锁 rtl 是可重入的,那么线程 T1 可以再次加锁成功;如果锁 rtl 是不可重入 ` * 的,那么线程 t 此时会被阻塞。*/
public class ReentrantLockExample {private final Lock rtl = new ReentrantLock();
int value;
public int get() {
// 获取锁
rtl.lock(); //②
try {return value;} finally {
// 保证锁能释放
rtl.unlock();}
}
public void addOne() {
// 获取锁
rtl.lock();
try {value = 1 + get(); //①
} finally {
// 保证锁能释放
rtl.unlock();}
}
可重入函数:多个线程可以同时调用该函数。
可重入函数是线程安全的。
非公平锁与公平锁
ReentrantLock 这个类有两个构造函数,一个是无参构造函数,一个是传入 fair 参数的构造函数。fair 参数代表的是锁的公平策略,如果传入 true 就表示需要构造一个公平锁,反 之则表示要构造一个非公平锁。
// 创建 ReentrantLock 时传入 true 是公平锁
private final Lock rtl = new ReentrantLock(true);
//false 或者不传值是非公平锁
private final Lock rtl = new ReentrantLock();
用锁的最佳实践
- 永远只再更新对象的成员变量时加锁。
- 永远只在访问可变的成员变量时加锁。
- 永远不再调用其它对象的方法时加锁。
- 减少所得持有时间,减小锁的粒度。
同步与异步
- 调用方法如果需要等待结果,就是同步;如果不需要等待结果就是异步。
- 同步是 Java 代码默认的处理方式。
如何实现程序支持异步:
- 异步调用: 调用方创建一个子线程,再子线程中执行方法调用。
- 异步方法: 被调用方;方法实现的时候,创建一个显得线程执行主要逻辑,主线程直接 return。
码字不易如果对你有帮助请给个关注
爱技术爱生活 QQ 群: 894109590