【JAVA多线程问题之死锁】
2014-10-02 15:18
357 查看
一、死锁是什么?
举个例子:两个人一起吃饭,每个人都拿了一只筷子,双方都在等待对方将筷子让给自己,结果两个人都吃不了饭。这种情况和计算机中的死锁情况很相似。
假设有两个线程,互相等待对方释放占有的锁,但是释放锁的条件又不可能形成,这时候死锁就形成了。
还是买票的问题,有的时候时会发生死锁的,将以前的代码改动一下,将会产生死锁:
死锁的现象:
如图所示,光标停在下一行不断闪烁,没有任何输出。
死锁具体是怎么形成的?以上面的输出为例:
线程0启动之后,由于标志变量为false,所以走的是else块,进入死循环,调用show方法,拿到this锁,然后继续拿到obj锁,顺利执行完毕之后,依次释放obj锁、this锁,然后开始进行第二次循环,拿到了this锁,但是将要拿到obj锁的时候,CPU切换到了线程1,线程1启动之后,由于flag已经是true,所以走的是if块,拿到了obj锁,刚要拿this锁,CPU切换到了线程0,线程0已经拿到了this锁,所以开始请求obj锁,但是obj锁在线程1手里,所以CPU切换到了线程1;线程1已经拿到了obj锁,所以它开始请求this锁,但是this锁在线程0手里,于是CPU切换到了线程0;..................
我们经过上面的分析,由于两个线程手里各自拿着对方的锁,相互请求但是没有让其中一方先释放锁的条件,所以CPU在两个线程之间不断切换,但是不会执行任何一方的任务。
总结死锁产生的条件:
1.有两个或者两个以上的锁。
2.同步嵌套(锁的嵌套)
死锁代码简单实例1:
死锁代码简单实例二:
可以观察发现两个代码基本相同,只是主函数中的方法略有不同,其中,第一个代码有99.9%的几率在第三行就锁上;第二个代码要到几百行才能锁上,甚至有时候锁不上。
第一种方法创建了两个实现了Runnable的接口对象,但是不影响结果;和第二个相比,第一个方法排除了不确定因素,是验证死锁程序的有效方法。
举个例子:两个人一起吃饭,每个人都拿了一只筷子,双方都在等待对方将筷子让给自己,结果两个人都吃不了饭。这种情况和计算机中的死锁情况很相似。
假设有两个线程,互相等待对方释放占有的锁,但是释放锁的条件又不可能形成,这时候死锁就形成了。
还是买票的问题,有的时候时会发生死锁的,将以前的代码改动一下,将会产生死锁:
/* 死锁的产生 */ class Ticket implements Runnable { Object obj=new Object(); boolean flag; private int sum=1000; public void run() { if(flag==true) { while(true) { synchronized(obj) { //->Thread1 show(); } } } else { while(true) show(); } } public synchronized void show() { //->Thread0 synchronized(obj) { if(sum>0) { try { Thread.sleep(10); } catch (InterruptedException e) { } System.out.println(Thread.currentThread().getName()+":function--"+sum--); } } } } public class Demo { public static void main(String args[]) { Ticket t=new Ticket(); t.flag=false; Thread t1=new Thread(t); Thread t2=new Thread(t); t1.start(); try//加入等待时间,让线程0启动 { Thread.sleep(10); } catch (InterruptedException e) { } t.flag=true; t2.start(); } }
死锁的现象:
如图所示,光标停在下一行不断闪烁,没有任何输出。
死锁具体是怎么形成的?以上面的输出为例:
线程0启动之后,由于标志变量为false,所以走的是else块,进入死循环,调用show方法,拿到this锁,然后继续拿到obj锁,顺利执行完毕之后,依次释放obj锁、this锁,然后开始进行第二次循环,拿到了this锁,但是将要拿到obj锁的时候,CPU切换到了线程1,线程1启动之后,由于flag已经是true,所以走的是if块,拿到了obj锁,刚要拿this锁,CPU切换到了线程0,线程0已经拿到了this锁,所以开始请求obj锁,但是obj锁在线程1手里,所以CPU切换到了线程1;线程1已经拿到了obj锁,所以它开始请求this锁,但是this锁在线程0手里,于是CPU切换到了线程0;..................
我们经过上面的分析,由于两个线程手里各自拿着对方的锁,相互请求但是没有让其中一方先释放锁的条件,所以CPU在两个线程之间不断切换,但是不会执行任何一方的任务。
总结死锁产生的条件:
1.有两个或者两个以上的锁。
2.同步嵌套(锁的嵌套)
死锁代码简单实例1:
class Demo implements Runnable { boolean flag; public Demo(){} public Demo(boolean flag) { this.flag=flag; } public void run() { if(flag) { while(true) { synchronized(Sour.lock1) { System.out.println("if---------lock1-------"); synchronized(Sour.lock2) { System.out.println("if-------lock2------"); } } } } else { while(true) { synchronized(Sour.lock2) { System.out.println("else---------lock2-------"); synchronized(Sour.lock1) { System.out.println("else-------lock1------"); } } } } } } class Sour { public static final Object lock1=new Object(); public static final Object lock2=new Object(); } public class DeadLockDemo { public static void main(String args[]) { Demo d1=new Demo(true); Demo d2=new Demo(false); Thread t1=new Thread(d1); Thread t2=new Thread(d2); t1.start(); t2.start(); } }
死锁代码简单实例二:
class Demo implements Runnable { boolean flag; public Demo(){} public Demo(boolean flag) { this.flag=flag; } public void run() { if(flag) { while(true) { synchronized(Sour.lock1) { System.out.println("if---------lock1-------"); synchronized(Sour.lock2) { System.out.println("if-------lock2------"); } } } } else { while(true) { synchronized(Sour.lock2) { System.out.println("else---------lock2-------"); synchronized(Sour.lock1) { System.out.println("else-------lock1------"); } } } } } } class Sour { public static final Object lock1=new Object(); public static final Object lock2=new Object(); } public class DeadLockDemo { public static void main(String args[]) { Demo d1=new Demo(); d1.flag=false; //Demo d2=new Demo(false); Thread t1=new Thread(d1); Thread t2=new Thread(d1); t1.start(); try { Thread.sleep(10); } catch (InterruptedException e) { } d1.flag=true; t2.start(); } }
可以观察发现两个代码基本相同,只是主函数中的方法略有不同,其中,第一个代码有99.9%的几率在第三行就锁上;第二个代码要到几百行才能锁上,甚至有时候锁不上。
第一种方法创建了两个实现了Runnable的接口对象,但是不影响结果;和第二个相比,第一个方法排除了不确定因素,是验证死锁程序的有效方法。
相关文章推荐
- java例程练习(多线程[死锁问题])
- java基础知识回顾之java Thread类学习(七)--java多线程安全问题(死锁)
- java 生产者消费者问题-多线程与死锁
- java 多线程 避免死锁 哲学家就餐问题
- JAVA 多线程死锁问题及解决
- java多线程第三天死锁问题
- JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题
- java 多线程 死锁 哲学家就餐问题
- java例程练习(多线程[死锁问题])
- java多线程第三天死锁问题
- JAVA基础 day11 多线程 同步代码块 死锁问题
- java语言基础(93)——多线程中的死锁问题
- java例程练习(多线程[死锁问题])
- java多线程死锁问题
- JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题
- java多线程第三天死锁问题
- 多线程死锁问题分析和解决[java]
- Java多线程死锁问题测试
- java多线程第三天死锁问题
- 黑马程序员:Java基础——多线程的死锁问题