产生死锁的四个必要条件
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 占有且等待:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3)不可强行占有:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
处理死锁的基本方法
- 死锁预防
通过设置某些限制条件,去破坏死锁的四个条件中的一个或几个条件,来预防发生死锁。但由于所施加的限制条件往往太严格,因而导致系统资源利用率和系统吞吐量降低。
- 死锁避免
允许前三个必要条件,但通过明智的选择,确保永远不会到达死锁点,因此死锁避免比死锁预防允许更多的并发。
- 死锁检测
不须实现采取任何限制性措施,而是允许系统在运行过程发生死锁,但可通过系统设置的检测机构及时检测出死锁的发生,并精确地确定于死锁相关的进程和资源,然后采取适当的措施,从系统中将已发生的死锁清除掉。
- 死锁解除
与死锁检测相配套的一种措施。当检测到系统中已发生死锁,需将进程从死锁状态中解脱出来。常用方法:撤销或挂起一些进程,以便回收一些资源,再将这些资源分配给已处于阻塞状态的进程。死锁检测盒解除有可能使系统获得较好的资源利用率和吞吐量,但在实现上难度也最大。
https://blog.csdn.net/rabbit_in_android/article/details/50530960
java 锁
- ReentrantLock
可重入锁
互斥锁
默认非公平锁,可设置公平锁
http://www.matools.com/api/java8
https://www.jianshu.com/p/c5cde8dfa6de
java锁思维导图
https://mm.edrawsoft.cn/template/5086
锁思维导图

常见锁的区别及适用场景
https://blog.csdn.net/u012658346/article/details/51188116
互斥锁、自旋锁优缺点和使用场景
https://blog.csdn.net/u010035604/article/details/84344576
悲观锁和乐观锁的使用场景与实现
- 乐观锁
使用版本号机制或CAS算法
代码实现(CAS算法):AtomicInteger
使用场景:多读。不在乎有脏读情况出现。适合针对一个变量,不适合代码块。
优点:能保证原子性。
缺点:脏读。ABA问题。
ABA问题解决办法:除了旧值比较外,还要比较时间戳。
- 悲观锁
使用场景:比较适合强一致性的场景。多写。
缺点:效率比较低,特别是读的并发低。
https://juejin.im/post/5b4977ae5188251b146b2fc8
ReentrantReadWriteLock读写锁
- 使用场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁。在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源;但是如果一个线程想去写这些共享资源,就不应该允许其他线程对该资源进行读和写的操作了。
volatile作用
https://www.cnblogs.com/zhengbin/p/5654805.html
java holdsLock()方法检测一个线程是否拥有锁
https://www.cnblogs.com/dolphin0520/p/3958019.html
线程池思维导图
https://blog.csdn.net/WuLex/article/details/103679550
常见java多线程面试题集合(用于过一遍,查漏补缺)
https://www.cnblogs.com/dolphin0520/p/3958019.html
线程平滑退出方法
- while使用标志位;
- shutdown处,根据条件判定线程是否已执行完。(最简单的做法是,sleep一段时间,但不严谨)
https://www.jianshu.com/p/613286f4245e
两种实现线程的方式
- extends Thread
class PrimeThread extendsThread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
}
}
// 启动方式
PrimeThread p = new PrimeThread(123);
p.start();
- extends Runnable
class PrimeRun extendsThread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
}
}
// 启动方式
PrimeRun p = new PrimeRun (123);
new Thread(p).start();
为了防止一个线程占用cpu过久,使用yield进行礼让
ThreadPoolExecutor
-
线程管理机制
image.png
- 工作队列最小为1,不能为0
- 线程池配置方案
https://www.cnblogs.com/zedosu/p/6665306.html
ConcurrentHashMap使用场景
- 在并发场景下,使并发效率更高
- 在并发场景下,线程安全
- 并发执行时,线程安全的容器只能保证自身的数据不被破坏,但无法保证业务的行为是否正确
java各种并发容器讲解(马士兵)
https://www.bilibili.com/video/av33688545/?p=6
生产者消费者问题,解决方案
- wait、notify
- ReentrantLock、condition
ReentrantLock可从入锁
- 用于代替synchronized
- 这是手工锁,需要手动释放
- .lock()写在try外面
- 公平锁
synchronized
- 一个同步方法可以调用另一个同步方法。
- 一个线程已经拥有某个对象的锁,再次申请的时候仍然会得到该对象的锁。
- 是重入锁。
- 程序在执行过程中,如果出现异常,默认情况锁会被释放,不然可能会发送不一致的情况。
- 不要以字符串变量作为锁对象。
- wait、notify
wait释放锁,notify不释放锁
wait和while 99%的情况都是用在一起
门闩:countDownLatch(并发性好)
volatile关键字
- 使一个变量在多线程间可见
- 会让所有线程都会督导变量的修改值
- 作用:一个线程修改了被volatile声明的变量,会告诉其他线程,这个值被修改了,请你到内存你再重新读取
- 使用场景
在变量运算不依赖当前值
变量不需要与其他状态变量共同参与不变约束
最佳实践就是使用volatile修饰的标志位来控制线程的停止
- volatile并不能保证多个线程共同修改变量是带来的不一致问题,也就说volatile不能替代synchronized
- 笔记总结来源:
https://www.bilibili.com/video/av33688545/?p=20
解决多线程安全问题的几种同步方法
- 同步代码块
- 同步方法
- 锁机制
网友评论