个人总结:什么情况下会导致线程死锁,遇到线程死锁该怎么解决?

一、死锁的定义:
所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进 。

二、死锁产生的必要条件:
**互斥条件:**线程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某 资源仅为一个线程所占有。此时若有其他线程请求该资源,则请求线程只能等待。

**不剥夺条件:**线程所获得的资源在未使用完毕之前,不能被其他线程强行夺走,即只能由获得该资源的线程自己来释放(只能是主动释放)。

**请求和保持条件:**线程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他线程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。

**循环等待条件:**存在一种线程资源的循环等待链,链中每一个线程已获得的资源同时被链中下一个线程所请求。即存在一个处于等待状态的线程集合{Pl, P2, …, pn},其中Pi等待的资源被P(i+1)占有(i=0, 1, …, n-1),Pn等待的资源被P0占有,如图所示:
在这里插入图片描述

产生死锁的一个例子代码:

1package itheima.com; 
2/**
3.* 一个简单的死锁类   
4.* 当 DeadLock 类的对象 flag==1 时(td1),先锁定 o1,睡眠 500 毫秒   
5.* 而 td1 在睡眠的时候另一个 flag==0 的对象(td2)线程启动,先锁定 o2,睡眠 500 毫秒
6.* td1 睡眠结束后需要锁定 o2 才能继续执行,而此时 o2 已被 td2 锁定;   
7.* td2 睡眠结束后需要锁定 o1 才能继续执行,而此时 o1 已被 td1 锁定;   
8.* td1、td2 相互等待,都需要得到对方锁定的资源才能继续执行,从而死锁。   
9.*/     
10public class DeadLock implements Runnable {     
11public int flag = 1;     
12//静态对象是类的所有对象共享的     
13private static Object o1 = new Object(), o2 = new Object();     
14public void run() {     
15.        System.out.println("flag=" + flag);     
16if (flag == 1) {     
17synchronized (o1) {     
18try {     
19.                    Thread.sleep(500);     
20} catch (Exception e) {     
21.                    e.printStackTrace();     
22}     
23synchronized (o2) {     
24.                    System.out.println("1");     
25}     
26}     
27}     
28if (flag == 0) {     
29synchronized (o2) {     
30try {     
31.                    Thread.sleep(500);     
32} catch (Exception e) {     
33.                    e.printStackTrace();     
34}     
35synchronized (o1) {     
36.                    System.out.println("0");     
37}     
38}     
39}     
40}       
41public static void main(String[] args) {        
42.        DeadLock td1 = new DeadLock();     
43.        DeadLock td2 = new DeadLock();     
44.        td1.flag = 1;     
45.        td2.flag = 0;     
46//td1,td2 都处于可执行状态,但 JVM 线程调度先执行哪个线程是不确定的。     47.        //td2 的 run()可能在 td1 的 run()之前运行     
48new Thread(td1).start();
49new Thread(td2).start();     
50}     
51}        

如何避免死锁 :

在有些情况下死锁是可以避免的。两种用于避免死锁的技术:

1)加锁顺序(线程按照一定的顺序加锁)

1package itheima.com; 
2public class DeadLock {     
3public int flag = 1;     
4//静态对象是类的所有对象共享的     
5private static Object o1 = new Object(), o2 = new Object();     
6public void money(int flag) { 
7this.flag=flag; 
8if( flag ==1){ 
9synchronized (o1) {     
10try {     
11.                     Thread.sleep(500);     
12} catch (Exception e) {     
13.                     e.printStackTrace();     
14}     
15synchronized (o2) {     
16.                     System.out.println("当前的线程是"+ 
17.                       Thread.currentThread().getName()+" "+"flag 的值"+"1");     18}     
19}         
20}         
21if(flag ==0){ 
22synchronized (o2) {     
23try {     
24.                    Thread.sleep(500);     
25} catch (Exception e) {     
26.                    e.printStackTrace();     
27}     
28synchronized (o1) {     
29.                    System.out.println("当前的线程是"+ 
30.                      Thread.currentThread().getName()+" "+"flag 的值"+"0");     31}     
32}       
33} 
34} 
3536public static void main(String[] args) {                
37final DeadLock td1 = new DeadLock();     
38final DeadLock td2 = new DeadLock();         
39.        td1.flag = 1;     
40.        td2.flag = 0;     
41//td1,td2 都处于可执行状态,但 JVM 线程调度先执行哪个线程是不确定的。     42.        //td2 的 run()可能在 td1 的 run()之前运行     
43final Thread t1=new Thread(new Runnable(){ 
44public void run() { 
45.    td1.flag = 1;  
46.    td1.money(1); 
47}         
48}); 
49.        t1.start(); 
50.        Thread t2= new Thread(new Runnable(){ 
51public void run() { 
52// TODO Auto-generated method stub 
53try { 
54//让 t2 等待 t1 执行完 
55.     t1.join();//核心代码,让 t1 执行完后 t2 才会执行 
56} catch (InterruptedException e) { 
57// TODO Auto-generated catch block 
58.     e.printStackTrace(); 
59} 
60.    td2.flag = 0; 
61.    td1.money(0); 
62}       
63}); 
64.        t2.start(); 
65}     
66}

结果:

当前的线程是 Thread-0 flag 的值 1
当前的线程是 Thread-1 flag 的值 0

2)加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)

1package itheima.com; 
2import java.util.concurrent.TimeUnit; 
3import java.util.concurrent.locks.Lock; 
4import java.util.concurrent.locks.ReentrantLock; 
5public class DeadLock { 
6public int flag = 1;     
7//静态对象是类的所有对象共享的     
8private static Object o1 = new Object(), o2 = new Object();     
9public void money(int flag) throws InterruptedException {    
10this.flag=flag; 
11if( flag ==1){ 
12synchronized (o1) {                      
13.                     Thread.sleep(500);                
14synchronized (o2) {     
15.                     System.out.println("当前的线程是"+ 
16.                       Thread.currentThread().getName()+" "+"flag 的值"+"1");     17}     
18}         
19}         
20if(flag ==0){ 
21synchronized (o2) {    
22.                    Thread.sleep(500);        
23synchronized (o1) {     
24.                    System.out.println("当前的线程是"+ 
25.                      Thread.currentThread().getName()+" "+"flag 的值"+"0");     26}     
27}       
28} 
29}     
3031public static void main(String[] args) {     
32final Lock lock = new ReentrantLock();   
33final DeadLock td1 = new DeadLock();     
34final DeadLock td2 = new DeadLock();         
35.        td1.flag = 1;     
36.        td2.flag = 0;     
37//td1,td2 都处于可执行状态,但 JVM 线程调度先执行哪个线程是不确定的。     38.        //td2 的 run()可能在 td1 的 run()之前运行     
3940final Thread t1=new Thread(new Runnable(){ 
41public void run() { 
42// TODO Auto-generated method stub 
43.    String tName = Thread.currentThread().getName(); 
4445.    td1.flag = 1;     
46try {   
47//获取不到锁,就等 5 秒,如果 5 秒后还是获取不到就返回 false   48.                    if (lock.tryLock(5000, TimeUnit.MILLISECONDS)) {   
49.                     System.out.println(tName + "获取到锁!");   
50} else {   
51.                     System.out.println(tName + "获取不到锁!");   
52return;   
53}   
54} catch (Exception e) {   
55.                    e.printStackTrace();   
56}   
5758try {                          
59.                 td1.money(1);                      
60} catch (Exception e) {   
61.                 System.out.println(tName + "出错了!!!");   
62} finally {   
63.                    System.out.println("当前的线程是"+Thread.currentThread().getName()+"释放锁!! ");   
64.                    lock.unlock();   
65}   
66}         
67}); 
68.        t1.start(); 
69.        Thread t2= new Thread(new Runnable(){ 
70public void run() { 
71.    String tName = Thread.currentThread().getName(); 
72// TODO Auto-generated method stub 
73.    td1.flag = 1;     
74try {   
75//获取不到锁,就等 5 秒,如果 5 秒后还是获取不到就返回 false   76.                    if (lock.tryLock(5000, TimeUnit.MILLISECONDS)) {   
77.                     System.out.println(tName + "获取到锁!");   
78} else {   
79.                     System.out.println(tName + "获取不到锁!");   
80return;   
81}   
82} catch (Exception e) {   
83.                    e.printStackTrace();   
84}   
85try {   
86.                 td2.money(0);   
87} catch (Exception e) {   
88.                 System.out.println(tName + "出错了!!!"); 
89} finally {   
90.                    System.out.println("当前的线程是"+Thread.currentThread().getName()+"释放锁!!");   
91.                    lock.unlock();   
92}  
93}    
94}); 
95.        t2.start();   
96}     
97}

打印结果:

Thread-0 获取到锁:
当前的线程是 Thread-0 flag 的值 1
当前的线程是 Thread-0 释放锁::
Thread-1 获取到锁:
当前的线程是 Thread-1 flag 的值 0
当前的线程是 Thread-1 释放锁::

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

改变世界的李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值