Java多线程 - ReentrantLock实际开发中的应用场景
1. 公平锁,线程排序执行,防饿死应用场景
公平锁原则必须按照锁申请时间上先到先得的原则分配机制场景;
1).实现逻辑 上(包括:软件中函数计算、业务先后流程;硬件中操作实现中顺序逻辑)的顺序排队机制的场景;
软件场景:用户交互View中对用户输入结果分析类,分析过程后面算法依赖上一步结果的场景,例如:推荐算法实现[根据性别、年龄筛选]、阻塞队列的实现;
硬件场景:需要先分析确认用户操作类型硬件版本或者厂家,然后发出操作指令;例如:自动售货机;
2).现实 生活中 时间排序的 公平原则:
例如:客服分配,必须是先到先服务,不能出现饿死现象;公平锁实现见上文:
公平锁与非公平锁的测试demo:逻辑代码实现那就没法子实现了;
阻塞队列的实现就是时间上的公平原则。
2. 非公平锁,效率的体现者
实际开发中最常用的的场景就是非公平锁,ReentrantLock无参构造默认就时候非公平锁;适应场景除了上面公平锁中提到的其他都是非公平锁的使用场景;
3. ReentrantLock.Condition线程通信
ReentrantLock.Condition线程通信是最长见的面试题,这里以最简单例子:两个线程之间交替打印 26英文字母和阿拉伯数字为demo:
private void alternateTask() {
ReentrantLock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Thread thread1 = new Thread(() -> {
try {
lock.lock();
for (int i = 65; i < 91; i++) {
System.out.println("----------thread1------- " + (char) i);
condition2.signal();
condition1.await();
}
condition2.signal();
} catch (Exception e) {
} finally {
lock.unlock();
}
});
Thread thread2 = new Thread(() -> {
try {
lock.lock();
for (int i = 0; i < 26; i++) {
System.out.println("----------thread2------- " + i);
condition1.signal();
condition2.await();
}
condition1.signal();
} catch (Exception e) {
} finally {
lock.unlock();
}
});
thread1.start();
thread2.start();
}
4.同步功能的使用
实现线程同步锁synchronized 功能【单例为例】
private Singleton() {
}
private static Singleton instance;
private static Lock lock = new ReentrantLock();
public static Singleton getInstance() {
lock.lock();
try {
if (instance == null) {
instance = new Singleton();
}
} finally {
lock.unlock();
}
return instance;
}
5. 中断杀器应用
ReentrantLock中lockInterruptibly()和lock()最大的区别就是中断相应问题:
lock()是支持中断相应的阻塞试的获取方式,因此即使主动中断了锁的持有者,但是它不能立即unlock(),仍然要机械版执行完所有操作才会释放锁。
lockInterruptibly()是 优先响应中断的,这样有个优势就是可以通过tryLock()、tryLock(timeout, TimeUnit.SECONDS)方法,中断优先级低的Task,及时释放资源给优先级更高的Task,甚至看到网上有人说可以做防止死锁的优化;
ReentrantLock lock = new ReentrantLock();
try {
lock.lockInterruptibly();
if (lock.tryLock(timeout, TimeUnit.SECONDS)) {
//TODO
}else{
//超时直接中断优先级低的Task
Thread.currentThread().interrupt();
lock.lock();
//TODO
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
6. 非重要任务Lock使用
优先级较低的操作让步给优先级更高的操作,提示代码效率/用户体验;忽略重复触发
1).用在定时任务时,如果任务执行时间可能超过下次计划执行时间,确保该有状态任务只有一个正在执行,忽略重复触发。
2).用在界面交互时点击执行较长时间请求操作时,防止多次点击导致后台重复执行(忽略重复触发)。
以上两种情况多用于进行非重要任务防止重复执行,(如:清除无用临时文件,检查某些资源的可用性,数据备份操作等)
tryLock()功能:如果已经获得锁立即返回fale,起到防止重复而忽略的效果
ReentrantLock lock = new ReentrantLock();
//防止重复执行,执行耗时操作,例如用户重复点击
if (lock.tryLock()) {
try {
//TO DO
} finally {
lock.unlock();
}
}
超时放弃
定时操作的例如:错误日志、定时过期缓存清理的操作,遇到优先级更高的操作占用资源时,暂时放弃本次操作下次再处理,可以起到让出CPU,提升用户体验;
ReentrantLock lock = new ReentrantLock();
try {
if (lock.tryLock(timeout, TimeUnit.SECONDS)) {
//TO DO
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}