java 线程死锁

来源:互联网 发布:java classloader原理 编辑:程序博客网 时间:2024/04/30 12:17

下面是一个由于同步导致线程死锁的例子:

package com.cn.gao;public class ThreadLock implements Runnable{private static Object obj1 = new Object();  //此处必须定义为static变量,这样才能使两个线程共享一个资源变量private static Object obj2 = new Object();  Boolean flag = true;@Overridepublic void run() {if(flag){synchronized(obj1){System.out.println(Thread.currentThread().getName() + ":我已经锁定obj1,休息2s就去锁定obj2");try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}synchronized(obj2){System.out.println(Thread.currentThread().getName() + ":我已锁定全部资源");}}}else{synchronized(obj2){System.out.println(Thread.currentThread().getName() + ":我已经锁定obj2,休息2s就去锁定obj1");try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}synchronized(obj1){System.out.println(Thread.currentThread().getName() + ":我已锁定全部资源");}}}}public static void main(String args[]){ThreadLock t1 = new ThreadLock();ThreadLock t2 = new ThreadLock();t1.flag = true;t2.flag = false;Thread thread1 = new Thread(t1,"线程1");Thread thread2 = new Thread(t2,"线程2");thread1.setPriority(Thread.MAX_PRIORITY);thread2.setPriority(Thread.MIN_PRIORITY);thread1.start();thread2.start();}}
输出:
<pre name="code" class="plain" style="color: rgb(56, 56, 56); font-size: 14px; line-height: 21.9999923706055px;">线程1:我已经锁定obj1,休息2s就去锁定obj2线程2:我已经锁定obj2,休息2s就去锁定obj1

那么为什么会产生死锁呢?
1.因为系统资源不足。
2.进程运行推进的顺序不合适。    
3.资源分配不当。
             
学过操作系统的朋友都知道:产生死锁的条件有四个:
1.互斥条件:所谓互斥就是进程在某一时间内独占资源。(就是说多个线程在某个时间内不能同时使用某一资源
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。(占有等待)(就是说一个线程需要拥有多个资源才能完成任务,他将一直占有已拥有的资源直到他拥有全部所需要的资源)
3.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。(所有的线程优先级相同,不能在别的线程没有释放资源的情况下强行夺走其资源)
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。(没有资源满足的线程无限期的等待


如何解决死锁,大家可以从死锁的四个条件去解决,只要破坏了一个必要条件,那么我们的死锁就解决了。在java中使用多线程的时候一定要考虑是否有死锁的问题哦。
  • 打破互斥条件
如果想要打破这个条件,就是要让多个线程共享资源,比如说一个读线程,还有一个写线程,如果他们可以同时操作同一个文件,则有可能读到脏数据。所以一般不从这方面考虑打破死锁

  • 打破占有等待
当检测到自己所需要的资源被别的线程占用,则立即释放自己占用的资源,或者等待某一固定时间,若还没有得到该资源,则立即释放自己所拥有的资源

  • 打破不剥夺条件
给所以的线程设定优先级,如有三个线程(优先级从高到低)A/B/C,当A需要某个资源时,如果此时C正在占用他,因为A的优先级高于C,所以C必须立马释放该资源

  • 打破循环等待条件
如果等待一段时间,还没有得到自己所需要的资源,则立马释放自己拥有的所有资源

下面是通过wait()方法释放对同步监视器的锁定,然后再通过notifyAll()释放对同步监视器的锁定
package com.cn.gao;public class ThreadLock implements Runnable{private static Object obj1 = new Object();  //此处必须定义为static变量,这样才能使两个线程共享一个资源变量private static Object obj2 = new Object();  Boolean flag = true;@Overridepublic void run() {if(flag){synchronized(obj1){System.out.println(Thread.currentThread().getName() + ":我已经锁定obj1,休息2s就去锁定obj2");try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//先调用obj1的wait()方法,导致当前线程等待,且当前线程会释放对同步监视器的锁定try {obj1.wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}synchronized(obj2){System.out.println(Thread.currentThread().getName() + ":我已锁定全部资源");}}}else{synchronized(obj2){System.out.println(Thread.currentThread().getName() + ":我已经锁定obj2,休息2s就去锁定obj1");try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}synchronized(obj1){System.out.println(Thread.currentThread().getName() + ":我已锁定全部资源");obj1.notifyAll();    //唤醒在此同步监视器上等待的所有线程}}}}public static void main(String args[]){ThreadLock t1 = new ThreadLock();ThreadLock t2 = new ThreadLock();t1.flag = true;t2.flag = false;Thread thread1 = new Thread(t1,"线程1");Thread thread2 = new Thread(t2,"线程2");thread1.start();thread2.start();}}
输出:
线程1:我已经锁定obj1,休息2s就去锁定obj2线程2:我已经锁定obj2,休息2s就去锁定obj1线程2:我已锁定全部资源线程1:我已锁定全部资源



虽然目前已经知道解决死锁的方法,但是具体应该怎么操作还不是很清楚。

比如说打破不剥夺条件里面:如有三个线程(优先级从高到低)A/B/C,当A需要某个资源时,如果此时C正在占用他,因为A的优先级高于C,所以C必须立马释放该资源

我是如何知道线程c正在占用该资源,如有人知道麻烦告知一下

0 0