基于白嫖黑马程序员白嫖视频:全面深入学习java并发编程,java基础进阶中级必会教程
目录
1 问题引入
synchronized关键字只能锁对象,就是说对象内部各个方法如果不是竞争状态的话,依然不能并行,一个对象只有一把锁,效率低。
2 活跃性
2.1 死锁
背景,当一个线程需要获得多把锁(占用多个资源)时,可能发生死锁情况;
2.2 哲学家就餐问题
5个哲学家,5只筷子,要么吃饭,要么思考,吃饭必须要2只筷子,当同时拿起右(左)手边的筷子时,就死锁了。
死锁发生的四个条件:
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
2.3 活锁
两个线程互相改变对方的结束条件,导致最后谁也无法结束;比如一个水池对象,两个线程一个放水,一个加水,都是加满或者放完结束,结果一直一个加一个放。
2.4 饥饿
某个线程一直得不到CPU的执行调度,它非常饥饿。
3 ReentrantLock
比起synchronized更加灵活:
- 可中断;
- 可以设置超时时间;
- 可以设置为公平锁;
- 支持多个条件变量;
4 基本语法
reentrantLock.lock();
try {
//临界区
}
finally {
reentrantLock.unlock();
}
5 可重入
同一线程,因为自己已经获取锁了 ,如果后面的代码有继续获得该锁的,则有权利再次获得这把锁。reentrantLock是支持可重入的。
6 可打断
本线程在等待获得锁的过程中,别的线程可以中止我的等待;
reentrantLock.lockInterruptibly();//lock不可以被interrupt
当在等待锁的过程中被打断,马上进入catch块,但是isInterrupted依然是false,和synchronized一样。
7 锁超时
打断是被动,锁超时是主动的。
boolean getLock = reentrantLock.tryLock(1, TimeUnit.SECONDS);//1s后去尝试得到锁
8 公平锁
synchronized的Monitor管理的锁不是一个公平的锁(BLOCKED线程获得锁的机会不同);
ReentrantLock默认是非公平,但是可以设置构造函数,使得变成公平锁,即先到阻塞队列的线程先获得锁,后到的后获得。
ReentrantLock reentrantLock = new ReentrantLock(true);//公平锁
本意是解决饥饿问题的,但是太强调顺序了又影响并发性,失去了多线程设计的本意。
9 条件变量(Condition)
和对象的obj.wait()和obj.notify()一样,ReentrantLock也有类似的设置;
ReentrantLock reentrantLock = new ReentrantLock(true); // 公平锁
Condition condition =reentrantLock.newCondition();// 获得条件变量
reentrantLock.lock();//加锁
try {
condition.await();//条件变量等待,会释放锁,此时可以被唤醒、设置超时、打断等等
} catch (InterruptedException e) {
e.printStackTrace();
}
condition.signalAll();//通知所有的condition等待线程
版权声明:本文为weixin_44215363原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。