转载请注明出处:http://blog.csdn.net/ns_code/article/details/17200937



当线程需要同时持有多个锁时,有可能产生死锁。考虑如下情形:

线程A当前持有互斥所锁lock1,线程B当前持有互斥锁lock2。接下来,当线程A仍然持有lock1时,它试图获取lock2,因为线程B正持有lock2,因此线程A会阻塞等待线程B对lock2的释放。如果此时线程B在持有lock2的时候,也在试图获取lock1,因为线程A正持有lock1,因此线程B会阻塞等待A对lock1的释放。二者都在等待对方所持有锁的释放,而二者却又都没释放自己所持有的锁,这时二者便会一直阻塞下去。这种情形称为死锁。

下面给出一个两个线程间产生死锁的示例,如下:

  1. public class Deadlock extends Object {
  2. private String objID;
  3. public Deadlock(String id) {
  4. objID = id;
  5. }
  6. public synchronized void checkOther(Deadlock other) {
  7. print("entering checkOther()");
  8. try { Thread.sleep(2000); }
  9. catch ( InterruptedException x ) { }
  10. print("in checkOther() - about to " + "invoke 'other.action()'");
  11. //调用other对象的action方法,由于该方法是同步方法,因此会试图获取other对象的对象锁
  12. other.action();
  13. print("leaving checkOther()");
  14. }
  15. public synchronized void action() {
  16. print("entering action()");
  17. try { Thread.sleep(500); }
  18. catch ( InterruptedException x ) { }
  19. print("leaving action()");
  20. }
  21. public void print(String msg) {
  22. threadPrint("objID=" + objID + " - " + msg);
  23. }
  24. public static void threadPrint(String msg) {
  25. String threadName = Thread.currentThread().getName();
  26. System.out.println(threadName + ": " + msg);
  27. }
  28. public static void main(String[] args) {
  29. final Deadlock obj1 = new Deadlock("obj1");
  30. final Deadlock obj2 = new Deadlock("obj2");
  31. Runnable runA = new Runnable() {
  32. public void run() {
  33. obj1.checkOther(obj2);
  34. }
  35. };
  36. Thread threadA = new Thread(runA, "threadA");
  37. threadA.start();
  38. try { Thread.sleep(200); }
  39. catch ( InterruptedException x ) { }
  40. Runnable runB = new Runnable() {
  41. public void run() {
  42. obj2.checkOther(obj1);
  43. }
  44. };
  45. Thread threadB = new Thread(runB, "threadB");
  46. threadB.start();
  47. try { Thread.sleep(5000); }
  48. catch ( InterruptedException x ) { }
  49. threadPrint("finished sleeping");
  50. threadPrint("about to interrupt() threadA");
  51. threadA.interrupt();
  52. try { Thread.sleep(1000); }
  53. catch ( InterruptedException x ) { }
  54. threadPrint("about to interrupt() threadB");
  55. threadB.interrupt();
  56. try { Thread.sleep(1000); }
  57. catch ( InterruptedException x ) { }
  58. threadPrint("did that break the deadlock?");
  59. }
  60. }

运行结果如下:

从结果中可以看出,在执行到other.action()时,由于两个线程都在试图获取对方的锁,但对方都没有释放自己的锁,因而便产生了死锁,在主线程中试图中断两个线程,但都无果。

大部分代码并不容易产生死锁,死锁可能在代码中隐藏相当长的时间,等待不常见的条件地发生,但即使是很小的概率,一旦发生,便可能造成毁灭性的破坏。避免死锁是一件困难的事,遵循以下原则有助于规避死锁:

1、只在必要的最短时间内持有锁,考虑使用同步语句块代替整个同步方法;

2、尽量编写不在同一时刻需要持有多个锁的代码,如果不可避免,则确保线程持有第二个锁的时间尽量短暂;

3、创建和使用一个大锁来代替若干小锁,并把这个锁用于互斥,而不是用作单个对象的对象级别锁;

转:【Java并发编程】之九:死锁(含代码)的更多相关文章

  1. java并发编程如何预防死锁

    在java并发编程领域已经有技术大咖总结出了发生死锁的条件,只有四个条件都发生时才会出现死锁: 1.互斥,共享资源X和Y只能被一个线程占用 2.占有且等待,线程T1已经取得共享资源X,在等待共享资源Y ...

  2. Java并发编程实战 04死锁了怎么办?

    Java并发编程文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 Java并发编程实战 03互斥锁 解决原子性问题 前提 在第三篇 ...

  3. java并发编程(九)死锁

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17200937 大部分代码并不容易产生死锁,死锁可能在代码中隐藏相当长的时间,等待不常见的条 ...

  4. Java并发编程(九):拓展

    java多线程死锁理解 Java多线程并发最佳实践 Spring与线程安全 HashMap与ConcurrentHashMap 关于java集合类HashMap的理解     ,      数据结构之 ...

  5. Java并发编程(九)安全发布

    之前讨论是如何将对象封闭在线程之中,这样可以减少一些并发带来的同步和可见性问题.但是在有些时候,我们希望在多个线程间共享对象,此时必须确保安全地进行共享. [不安全发布的示例] 可见性问题:其他线程看 ...

  6. Java并发编程(九)-- 进程饥饿和公平锁

    上一章已经提到“如果一个进程被多次回滚,迟迟不能占用必需的系统资源,可能会导致进程饥饿”,本文我们详细的介绍一下“饥饿”和“公平”. Java中导致饥饿的原因 在Java中,下面三个常见的原因会导致线 ...

  7. Java并发编程(九)并发容器

    并发容器的简单介绍: ConcurrentHashMap代替同步的Map(Collections.synchronized(new HashMap())),众所周知,HashMap是根据散列值分段存储 ...

  8. 【Java并发编程】:死锁

    当线程需要同时持有多个锁时,有可能产生死锁.考虑如下情形: 线程A当前持有互斥所锁lock1,线程B当前持有互斥锁lock2.接下来,当线程A仍然持有lock1时,它试图获取lock2,因为线程B正持 ...

  9. Java并发编程(九)线程间协作(下)

    上篇我们讲了使用wait()和notify()使线程间实现合作,这种方式很直接也很灵活,但是使用之前需要获取对象的锁,notify()调用的次数如果小于等待线程的数量就会导致有的线程会一直等待下去.这 ...

  10. java并发编程(九)----(JUC)CyclicBarrier

    上一篇我们介绍了CountDownlatch,我们知道CountDownlatch是"在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待",即CountDownL ...

随机推荐

  1. 编写一个矩形类,私有数据成员为矩形的长( len)和宽(wid),wid设置为0,有参构造函数设置和的值,另外,类还包括矩形的周长、求面积、取矩形的长度、取矩形的长度、取矩形的宽度、修改矩形的长度和宽度为对应的形参值等公用方法。

    class Rectangle { private double len, wid; public Rectangle()//求矩形周长 { len = 0; wid = 0; } public Re ...

  2. Ruby01: Beginner

    中整個早上都忙著作業,看來是假期懶了一下現在現眼報吧哈哈.在上課之前發一下Ruby 的首章,算是倉促的開始吧. puts puts "Once upon a time... there's ...

  3. HDU 3682 To Be an Dream Architect:查重【三维坐标系中点在实数上的映射】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3682 题意: 有一个n*n*n的立方体,左下角坐标为(1,1,1),接下来进行m次操作. 每个操作形如 ...

  4. RMAN 备份异机恢复 并创建新DBID

    测试平台信息: Oracle:11gR2 操作系统:Redhat 5.5 Target DB:dave   几点说明: (1)RMAN 异机恢复的时候,db_name必须相同. 如果说要想改成其他的实 ...

  5. oracle 表空间 表权限 用户

    启动数据库命令分为三个阶段: 1.查看所有用户:select * from dba_user;select * from all_users;select * from user_users;2.查看 ...

  6. 机器学习笔记——拉格朗日乘子法和KKT条件

    拉格朗日乘子法是一种寻找多元函数在一组约束下的极值方法,通过引入拉格朗日乘子,可将有m个变量和n个约束条件的最优化问题转化为具有m+n个变量的无约束优化问题.在介绍拉格朗日乘子法之前,先简要的介绍一些 ...

  7. Netty笔记——技术点汇总

    目录 · Linux网络IO模型 · 文件描述符 · 阻塞IO模型 · 非阻塞IO模型 · IO复用模型 · 信号驱动IO模型 · 异步IO模型 · BIO编程 · 伪异步IO编程 · NIO编程 · ...

  8. meta标签的name和http-equiv属性

    META标签是HTML语言HEAD区的一个辅助性标签,它位于HTML文档头部的<HEAD>标记和<TITLE>标记之间,它提供用户不可见的信息.META标签有两个重要的属性:H ...

  9. oracle撤销表空间和回滚段

    /* 撤销表空间 */ 通过使用撤销技术,能够为Oracle数据库提供以下功能: * 使用ROLLBACK语句撤销事务 * 进行数据库恢复 * 提供数据的读一致性 Oracle强烈建议DBA在Orac ...

  10. TechSmith Camtasia Studio屏幕录像编辑工具

    TechSmith Camtasia Studio屏幕录像编辑工具... --------------------------------------------------------- ----- ...