黑马程序员技术交流社区

标题: 多线程如何解决死锁问题? [打印本页]

作者: Ф福@ 御    时间: 2014-5-20 20:15
标题: 多线程如何解决死锁问题?
是不是要确认锁是什么,并且要十分清楚线程的状态?

作者: Sevenette    时间: 2014-5-21 17:09
本帖最后由 Sevenette 于 2014-5-21 17:12 编辑

死锁一种情况是两个锁互相嵌套,运行时不和谐两个进程都掐着锁不放这是毕老师将时的例子0.0 可以愉快的copy去玩玩看...

代码应该能看懂吧0.0?视频大概是在day13-day14 (我是35天的那个视频)


  1. class Ticket implements Runnable
  2. {
  3.         private  int num = 100;
  4.         Object obj = new Object();
  5.         boolean flag = true;
  6.         public void run()
  7.         {
  8.                 if(flag)
  9.                         while(true)
  10.                         {
  11.                                 synchronized(obj)
  12.                                 {
  13.                                         show();
  14.                                 }
  15.                         }
  16.                 else
  17.                         while(true)
  18.                                 this.show();
  19.         }

  20.         public synchronized void show()
  21.         {
  22.                 synchronized(obj)
  23.                 {
  24.                         if(num>0)
  25.                         {
  26.                                 try{Thread.sleep(10);}catch (InterruptedException e){}
  27.                                 System.out.println(Thread.currentThread().getName()+".....sale...."+num--);
  28.                         }
  29.                 }
  30.         }
  31. }

  32. class DeadLockDemo
  33. {
  34.         public static void main(String[] args)
  35.         {
  36.                 Ticket t = new Ticket();

  37.                 Thread t1 = new Thread(t);
  38.                 Thread t2 = new Thread(t);

  39.                 t1.start();
  40.                 try{Thread.sleep(10);}catch(InterruptedException e){}
  41.                 t.flag = false;
  42.                 t2.start();
  43.         }
  44. }
复制代码

还有一种情况的是在同步里,生产消费模型,notify()方法唤醒本方线程造成所有线程都处于wait()状态,形成死锁。把notify()改成notifyAll()方法就能解决了~

  1. /*
  2. 生产者,消费者。

  3. 多生产者,多消费者的问题。
  4. if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。
  5. while判断标记,解决了线程获取执行权后,是否要运行!

  6. notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。
  7. notifyAll解决了本方线程一定会唤醒对方线程的问题。

  8. */

  9. class Resource
  10. {
  11.         private String name;
  12.         private int count = 1;
  13.         private boolean flag = false;
  14.         public synchronized void set(String name)//  
  15.         {
  16.                 while(flag)
  17.                         try{this.wait();}catch(InterruptedException e){}//   t1    t0
  18.                
  19.                 this.name = name + count;//烤鸭1  烤鸭2  烤鸭3
  20.                 count++;//2 3 4
  21.                 System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
  22.                 flag = true;
  23.                 notifyAll();
  24.         }

  25.         public synchronized void out()//  t3
  26.         {
  27.                 while(!flag)
  28.                         try{this.wait();}catch(InterruptedException e){}        //t2  t3
  29.                 System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);//消费烤鸭1
  30.                 flag = false;
  31.                 notifyAll();
  32.         }
  33. }

  34. class Producer implements Runnable
  35. {
  36.         private Resource r;
  37.         Producer(Resource r)
  38.         {
  39.                 this.r = r;
  40.         }
  41.         public void run()
  42.         {
  43.                 while(true)
  44.                 {
  45.                         r.set("烤鸭");
  46.                 }
  47.         }
  48. }

  49. class Consumer implements Runnable
  50. {
  51.         private Resource r;
  52.         Consumer(Resource r)
  53.         {
  54.                 this.r = r;
  55.         }
  56.         public void run()
  57.         {
  58.                 while(true)
  59.                 {
  60.                         r.out();
  61.                 }
  62.         }
  63. }
  64. class  ProducerConsumerDemo
  65. {
  66.         public static void main(String[] args)
  67.         {
  68.                 Resource r = new Resource();
  69.                 Producer pro = new Producer(r);
  70.                 Consumer con = new Consumer(r);

  71.                 Thread t0 = new Thread(pro);
  72.                 Thread t1 = new Thread(pro);
  73.                 Thread t2 = new Thread(con);
  74.                 Thread t3 = new Thread(con);
  75.                 t0.start();
  76.                 t1.start();
  77.                 t2.start();
  78.                 t3.start();
  79.         }
  80. }
复制代码



或者运用1.5的新特性:Lock和Condition解决。只有Resource资源类中的方法有改动 生产、消费类的代码和上面是一样的 我就不粘贴了0.0
  1. /*
  2. jdk1.5以后将同步和锁封装成了对象。
  3. 并将操作锁的隐式方式定义到了该对象中,
  4. 将隐式动作变成了显示动作。

  5. Lock接口: 出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。
  6. 同时更为灵活。可以一个锁上加上多组监视器。
  7. lock():获取锁。
  8. unlock():释放锁,通常需要定义finally代码块中。

  9. Condition接口:出现替代了Object中的wait notify notifyAll方法。
  10.                         将这些监视器方法单独进行了封装,变成Condition监视器对象。
  11.                         可以任意锁进行组合。
  12. await();
  13. signal();
  14. signalAll();

  15. */
  16. import java.util.concurrent.locks.*;

  17. class Resource
  18. {
  19.         private String name;
  20.         private int count = 1;
  21.         private boolean flag = false;

  22. //        创建一个锁对象。
  23.         Lock lock = new ReentrantLock();

  24.         //通过已有的锁获取该锁上的监视器对象。
  25. //        Condition con = lock.newCondition();

  26.         //通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。
  27.         Condition producer_con = lock.newCondition();
  28.         Condition consumer_con = lock.newCondition();
  29.         
  30.         public  void set(String name)//  t0 t1
  31.         {
  32.                 lock.lock();
  33.                 try {
  34.                         while(flag)
  35. //                        try{lock.wait();}catch(InterruptedException e){}//   t1    t0
  36.                         try{producer_con.await();}catch(InterruptedException e){}//   t1    t0
  37.                
  38.                         this.name = name + count;//烤鸭1  烤鸭2  烤鸭3
  39.                         count++;//2 3 4
  40.                         System.out.println(Thread.currentThread().getName()+"...生产者5.0..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
  41.                         flag = true;
  42. //                        notifyAll();
  43. //                        con.signalAll();
  44.                         consumer_con.signal();
  45.                 }finally
  46.                 {
  47.                         lock.unlock();
  48.                 }
  49.         }

  50.         public  void out()// t2 t3
  51.         {
  52.                 lock.lock();
  53.                 try
  54.                 {
  55.                         while(!flag)
  56. //                        try{this.wait();}catch(InterruptedException e){}        //t2  t3
  57.                         try{cousumer_con.await();}catch(InterruptedException e){}        //t2  t3
  58.                         System.out.println(Thread.currentThread().getName()+"...消费者.5.0......."+this.name);//消费烤鸭1
  59.                         flag = false;
  60. //                        notifyAll();
  61. //                        con.signalAll();
  62.                         producer_con.signal();
  63.                 }
  64.                 finally
  65.                 {
  66.                         lock.unlock();
  67.                 }
  68.         }
  69. }
复制代码





作者: 艮昕辶    时间: 2014-5-21 17:12
标题: 红色代码比较关键 其他的东西换个场景就不能按老毕的写了
本帖最后由 艮昕辶 于 2014-5-21 17:16 编辑
  1. <font color="#ff0000">Lock lock = new ReentrantLock();</font>
  2.         //通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。
  3.       <font color="#ff0000">  Condition producer_con = lock.newCondition();
  4.         Condition consumer_con = lock.newCondition();</font>

  5.         
  6.         public  void set(String name)//  t0 t1
  7.         {
  8.              <font color="#ff0000">   lock.lock();</font>
  9.                 try
  10.                 {
  11.                         while(flag)
  12.                         try{<font color="#ff0000">producer_con.await();</font>}catch(InterruptedException e){}//   t1    t0
  13.                
  14.                         this.name = name + count;//烤鸭1  烤鸭2  烤鸭3
  15.                         count++;//2 3 4
  16.                         System.out.println(Thread.currentThread().getName()+"...生产者5.0..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
  17.                         flag = true;
  18.                       <font color="#ff0000">  consumer_con.signal();</font>
  19.                 }
  20.                 finally
  21.                 {
  22.                       <font color="#ff0000">  lock.unlock();</font>
  23.                 }
  24.                
  25.         }

  26.         public  void out()// t2 t3
  27.         {
  28.               <font color="#ff0000">  lock.lock();</font>
  29.                 try
  30.                 {   
  31.                         try{cousumer_con.await();}catch(InterruptedException e){}        //t2  t3
  32.                         System.out.println(Thread.currentThread().getName()+"...消费者.5.0......."+this.name);//消费烤鸭1
  33.                         flag = false;

  34.                         <font color="#ff0000">producer_con.signal();</font>
  35.                 }
  36.                 finally
  37.                 {
  38.                       <font color="#ff0000">  lock.unlock();</font>
  39.                 }
  40.                
  41.         }
复制代码

作者: Ф福@ 御    时间: 2014-5-21 20:24
谢谢、指导!!!!
作者: Hosing    时间: 2014-7-3 15:56
synchronized同步




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2