Java 多线程编程之七:死锁(附源代码)

来源:互联网 发布:南京中兴新软件 编辑:程序博客网 时间:2024/06/11 18:26

Java 多线程编程之七:死锁(附源代码)

源代码下载
        多线程编程中,线程死锁也是一个比较有趣的问题。然而死锁发生的可能性很小,正因如此,大家可能对此不是很熟悉。但是死锁并不是不重要,因为它确确实实存在着,随时会出现在我们的程序之中。很多朋友面试的时候都遇到过这样类似的一个编程题:使用 Java 写一个死锁。问题不是很难,但是由于大家现实中处理的比较少,还真难住了一部分人。本文列举了一个简单但又不失为经典的死锁的源代码,并解释了死锁发生的原因。相信读者看过之后对死锁会有更进一步的认识!
        死锁发生的原因一般是两个对象的锁相互等待造成的。比如线程 1 先拿到了对象 A 的对象锁,线程 2 先拿到了对象 B 的对象锁。线程 1 这时候要求拿到对象 B 的对象锁,因为对象 B 的对象锁暂时被线程 2 所持有,所以线程 1 只能抱着对象 A 的对象锁等待线程 2 释放掉对象 B 的对象锁。而如果这个时候,持有对象 B 的对象锁的线程 2 要求访问对象 A 的对象锁,因为对象 A 的对象锁暂时被线程 1 所持有,所以线程 2 只能抱着对象 B 的对象锁等待线程 1 释放掉对象 A 的对象锁。这个时候两个线程就陷入了互相等待的僵局之中。程序就进入了死锁的状态,除非你手工停掉这个程序,否则它将永久地僵持下去。
        是不是有点绕?嘿嘿,如果你弄明白了对象锁的概念,死锁的原因也就一目了然。关于对象锁,作者在上一篇博客《Java 多线程编程之六:线程之间的通信(附源代码)》中有所介绍,这里就不再赘述了。
        用代码说明问题,直接看代码演示。
死锁例子-资源源代码

[java] view plaincopyprint?
  1. package com.defonds.deadlock;  
  2. /** 
  3.  *  
  4.  *  
  5.  * 项目名称:ThreadDeadLock 
  6.  * 类名称:Resource 
  7.  * 类描述:资源类,用于代表线程竞争的数据资源 
  8.  * 创建人:Defonds 
  9.  * 创建时间:2010-1-26 下午02:01:16 
  10.  * 修改人:Defonds 
  11.  * 修改时间:2010-1-26 下午02:01:16 
  12.  * 修改备注: 
  13.  * @version  
  14.  * 
  15.  */  
  16. public class Resource {  
  17.       
  18.     private int value;//资源的属性  
  19.     public int getValue() {  
  20.         return value;  
  21.     }  
  22.     public void setValue(int value) {  
  23.         this.value = value;  
  24.     }  
  25. }  

死锁例子-资源管理器源代码

[java] view plaincopyprint?
  1. package com.defonds.deadlock;  
  2. /** 
  3.  *  
  4.  *  
  5.  * 项目名称:ThreadDeadLock 
  6.  * 类名称:ResourceManager 
  7.  * 类描述:资源管理类,对资源数据操作的接口 
  8.  * 创建人:Defonds 
  9.  * 创建时间:2010-1-26 下午02:04:59 
  10.  * 修改人:Defonds 
  11.  * 修改时间:2010-1-26 下午02:04:59 
  12.  * 修改备注: 
  13.  * @version  
  14.  * 
  15.  */  
  16. public class ResourceManager {  
  17.       
  18.     /** 
  19.      * 管理的两个资源 
  20.      */  
  21.     private Resource resourceA = new Resource();  
  22.     private Resource resourceB = new Resource();  
  23.       
  24.     /** 
  25.      * 创建一个新的实例 ResourceManager. 
  26.      */  
  27.     public ResourceManager(){  
  28.         this.resourceA.setValue(0);  
  29.         this.resourceB.setValue(0);  
  30.     }  
  31.       
  32.     /** 
  33.      * 资源的读取 
  34.      */  
  35.     public int read(){  
  36.         synchronized(this.resourceA){  
  37.             System.out.println(Thread.currentThread().getName() + "线程拿到了资源 resourceA 的对象锁");  
  38.             synchronized(resourceB){  
  39.                 System.out.println(Thread.currentThread().getName() + "线程拿到了资源 resourceB 的对象锁");  
  40.                 return this.resourceA.getValue() + this.resourceB.getValue();  
  41.             }  
  42.         }  
  43.     }  
  44.       
  45.     /** 
  46.      * 资源的改写 
  47.      */  
  48.     public void write(int a,int b){  
  49.         synchronized(this.resourceB){  
  50.             System.out.println(Thread.currentThread().getName() + "线程拿到了资源 resourceB 的对象锁");  
  51.             synchronized(this.resourceA){  
  52.                 System.out.println(Thread.currentThread().getName() + "线程拿到了资源 resourceA 的对象锁");  
  53.                 this.resourceA.setValue(a);  
  54.                 this.resourceB.setValue(b);  
  55.             }  
  56.         }  
  57.     }  
  58. }  

死锁例子-自定义线程源代码

[java] view plaincopyprint?
  1. package com.defonds.deadlock;  
  2. /** 
  3.  *  
  4.  *  
  5.  * 项目名称:ThreadDeadLock 
  6.  * 类名称:CustomizeThread 
  7.  * 类描述:自定义线程类 
  8.  * 创建人:Defonds 
  9.  * 创建时间:2010-1-26 下午02:29:01 
  10.  * 修改人:Defonds 
  11.  * 修改时间:2010-1-26 下午02:29:01 
  12.  * 修改备注: 
  13.  * @version  
  14.  * 
  15.  */  
  16. public class CustomizeThread extends Thread {  
  17.     private ResourceManager resourceManger;//资源管理类的私有引用,通过此引用可以通过其相关接口对资源进行读写  
  18.     private int a,b;//将要写入资源的数据  
  19.       
  20.     /** 
  21.      *  
  22.      * 创建一个新的实例 CustomizeThread. 
  23.      * @param resourceManger 
  24.      * @param a 
  25.      * @param b 
  26.      */  
  27.     public CustomizeThread(ResourceManager resourceManger,int a,int b){  
  28.         this.resourceManger = resourceManger;  
  29.         this.a = a;  
  30.         this.b = b;  
  31.     }  
  32.       
  33.     /** 
  34.      * 重写 java.lang.Thread 的 run 方法 
  35.      */  
  36.     public void run(){  
  37.         /** 
  38.          * 为了演示死锁的出现,这里对资源进行反复读写 
  39.          * 实际业务中可能只读写一次 
  40.          */  
  41.         while(true){  
  42.             this.resourceManger.read();  
  43.             this.resourceManger.write(this.a, this.b);  
  44.         }  
  45.     }  
  46. }  

死锁例子-程序入口源代码

[java] view plaincopyprint?
  1. package com.defonds.deadlock;  
  2. /** 
  3.  *  
  4.  *  
  5.  * 项目名称:ThreadDeadLock 
  6.  * 类名称:DeadLockApp 
  7.  * 类描述:死锁程序入口 
  8.  * 创建人:Defonds 
  9.  * 创建时间:2010-1-26 下午02:37:27 
  10.  * 修改人:Defonds 
  11.  * 修改时间:2010-1-26 下午02:37:27 
  12.  * 修改备注: 
  13.  * @version  
  14.  * 
  15.  */  
  16. public class DeadLockApp {  
  17.     public static void main(String[] args) {  
  18.           
  19.         /** 
  20.          * 死锁演示线程初始化 
  21.          */  
  22.         ResourceManager resourceManager = new ResourceManager();  
  23.         CustomizeThread customizedThread0 = new CustomizeThread(resourceManager,1,2);  
  24.         CustomizeThread customizedThread1 = new CustomizeThread(resourceManager,2,4);  
  25.           
  26.         /** 
  27.          * 死锁演示线程启动 
  28.          */  
  29.         customizedThread0.start();  
  30.         customizedThread1.start();  
  31.     }  
  32. }  

        下面一次执行本代码时死锁发生的控制台输出片段:
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceA 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-0线程拿到了资源 resourceB 的对象锁
Thread-1线程拿到了资源 resourceA 的对象锁

        由上述例子可以看出,一旦两个线程互相等待的局面出现,死锁现象就不可避免地发生了。

0 0
原创粉丝点击