java线程研究---(10)Thread同步:死锁
来源:互联网 发布:知金教育的含金量如何 编辑:程序博客网 时间:2024/05/21 17:00
死锁
synchronized块的乱用,会造成死锁。
下面来看看死锁形成的大致情况:
- 线程T1,执行线程对象A
- 线程T2,执行线程对象B
- 线程对象A,里面有加锁的代码需要获得自己的锁,并且同时有另外一个加锁的代码需要获得线程对象B的锁。
- 线程对象B,里面有加锁的代码需要获得自己的锁,并且同时有另外一个加锁的代码需要获得线程对象A的锁。
- 简言之:
- 线程对象A在获得自己的锁的时候,需要获得线程对象B的锁
- 线程对象B在获得自己的锁的时候,需要获得线程对象A的锁
- 那么这两个对象都在占用自己的锁的时候,想要获得对方对象的锁。
- 因此,这两个对象都在等锁的池(lock pool)中,都处于等待拿锁的状态。
- 所以死锁就形成了——两个对象会无限的等待下去。。。
来看看死锁示例代码:
DeadThreadA.java
package thread;public class DeadThreadA implements Runnable {public DeadThreadBdeadThreadB;// 想拿到对方线程对象的锁,就得先获得引用private inti= 0;private intj= 0;@Overridepublic void run() {while (true) {synchronized (this) { // 首先占用自己对象的锁if (i >= 10)break;i++;for (int j = 0; j < 10000000l; j++);System.out.println(Thread.currentThread().getName() + ": i=" + i);while (true) {synchronized (deadThreadB) { // 在占用自己对象的锁的同时,需要获得deadThreadB的锁if (j >= 10) {break;}j++;for (int j = 0; j < 10000000l; j++);System.out.println(Thread.currentThread().getName() + ": j=" + j);}}}}}}
DeadThreadB.java
package thread;public class DeadThreadB implements Runnable {public DeadThreadAdeadThreadA;// 想拿到对方线程对象的锁,就得先获得引用private inti= 0;private intj= 0;@Overridepublic void run() {while (true) {synchronized (this) { // 首先占用自己对象的锁if (i >= 10)break;i++;for (int j = 0; j < 10000000l; j++);System.out.println(Thread.currentThread().getName() + ": i= " + i);while (true) {synchronized (deadThreadA) { // 在占用自己对象的锁的同时,需要获得deadThreadA的锁if (j >= 10) {break;}j++;for (int j = 0; j < 10000000l; j++);System.out.println(Thread.currentThread().getName() + ": j= " + j);}}}}}}
代码的几点说明:
- synchronized()块,只支持传入对象,如果想拿对方线程对象的锁,那么首先得获得对方线程对象的引用。
- 当前的两个 线程对象,首先是各自已经占用了自己的锁,同时再,都尝试去拿对方的锁。
- 所以,先synchronized (this),在占用自己的锁的同时,(没有释放自己的锁)再去拿对方的锁:synchronized (deadThreadB), synchronized (deadThreadA)
- 也就是说,当前线程,要同时拿两个锁:首先是拿到自己锁,然后再去尝试拿对方的锁。
执行类,如下
DeadThreadMain.java
package thread;public class DeadThreadMain {public static void main(String ab[]) {DeadThreadA a = new DeadThreadA();DeadThreadB b = new DeadThreadB();b.deadThreadA = a; // 获得对方线程对象的引用a.deadThreadB = b; // 获得对方线程对象的引用Thread t1 = new Thread(a); Thread t2 = new Thread(b);t1.start();t2.start();}}
控制台就打印这么多,之后程序是一直运行的,但是就像死循环一样,永不停止了:
Thread-1: i= 1
Thread-0: i=1
Thread-0: i=1
根据示例代码,来具体讲一下死锁过程:
- t1线程启动的时候,首先占用了a对象的锁
- t2线程启动的时候,首先占用了b对象的锁
- t1线程占用了a对象的锁的同时,尝试拿b对象的锁:b对象的锁,一直在t2线程手里
- t2线程占用了b对象的锁的同时,尝试拿a对象的锁:a对象的锁,一直在t1线程手里
- t1和t2线程都处于等待拿对方的锁的状态,
- 死锁产生
0 0
- java线程研究---(10)Thread同步:死锁
- Java笔记(4)-线程、Thread、Runable、开子线程、线程运行状态、线程同步、线程死锁
- java线程研究---(8)Thread同步:锁的概念
- java线程研究---(9)Thread同步:如何加锁
- JAVA线程同步与死锁
- java线程同步之死锁
- Java--多线程Thread(实现,并发并行,同步死锁,单例,线程组池)
- Java Thread 线程同步、锁
- Java笔记六.线程同步、线程死锁
- 多线程-4-线程同步、线程安全问题及死锁研究
- java线程研究---(7)Thread同步:多线程数据共用会产生问题
- 线程同步 线程死锁
- 线程同步/线程死锁
- java线程同步之死锁问题
- Java线程同步与死锁认识
- Java线程的同步与死锁
- Java 线程同步与死锁 学习笔记
- Java多线程之线程同步和死锁
- 来自《剑指offer》 二叉树镜像
- 控制台输出
- 我的openwrt学习笔记(三十二):openwrt 的UCI
- 类似于Guava Function<F, T>实现
- Android开发之APN网络切换
- java线程研究---(10)Thread同步:死锁
- ListView为什么要使用convertView和ViewHolder
- Android Material Design Library系列教程(三)
- python文件从windows到linux换行符的变化
- 开发笔记之NSTable 排序
- 整数划分系列问题(动态规划)
- ios中UI控件的继承关系
- 唐巧的博客地址
- iOS中的模糊效果