zoukankan      html  css  js  c++  java
  • 【JAVA多线程问题之死锁】

    一、死锁是什么?

    举个例子:两个人一起吃饭,每个人都拿了一只筷子,双方都在等待对方将筷子让给自己,结果两个人都吃不了饭。这种情况和计算机中的死锁情况很相似。

    假设有两个线程,互相等待对方释放占有的锁,但是释放锁的条件又不可能形成,这时候死锁就形成了。

    还是买票的问题,有的时候时会发生死锁的,将以前的代码改动一下,将会产生死锁:

     1 /*
     2 死锁的产生
     3 */
     4 class Ticket implements Runnable
     5 {
     6     Object obj=new Object();
     7     boolean flag;
     8     private int sum=1000;
     9     public void run()
    10     {
    11             if(flag==true)
    12             {
    13                 while(true)
    14                 {
    15                     synchronized(obj)
    16                     {
    17                         //->Thread1
    18                         show();
    19                     }
    20                 }
    21             }
    22             else
    23             {
    24                 while(true)
    25                 show();
    26             }
    27     }
    28     public synchronized void show()
    29     {
    30         //->Thread0
    31         synchronized(obj)
    32         {
    33             if(sum>0)
    34             {
    35                 try
    36                 {
    37                     Thread.sleep(10);
    38                 }
    39                 catch (InterruptedException e)
    40                 {
    41                 }
    42                 System.out.println(Thread.currentThread().getName()+":function--"+sum--);
    43             }
    44         }
    45     }
    46 }
    47 public class Demo
    48 {
    49     public static void main(String args[])
    50     {
    51         Ticket t=new Ticket();
    52         t.flag=false;
    53         Thread t1=new Thread(t);
    54         Thread t2=new Thread(t);
    55         t1.start();
    56 
    57         try//加入等待时间,让线程0启动
    58         {
    59             Thread.sleep(10);
    60         }
    61         catch (InterruptedException e)
    62         {
    63 
    64         }
    65         t.flag=true;
    66         t2.start();
    67     }
    68 }

    死锁的现象:

    如图所示,光标停在下一行不断闪烁,没有任何输出。

    死锁具体是怎么形成的?以上面的输出为例:

    线程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:

     1 class Demo implements Runnable
     2 {
     3     boolean flag;
     4     public Demo(){}
     5     public Demo(boolean flag)
     6     {
     7         this.flag=flag;
     8     }
     9     public void run()
    10     {
    11         if(flag)
    12         {
    13             while(true)
    14             {
    15                 synchronized(Sour.lock1)
    16                 {
    17                     System.out.println("if---------lock1-------");
    18                     synchronized(Sour.lock2)
    19                     {
    20                         System.out.println("if-------lock2------");
    21                     }
    22                 }
    23             }
    24         }
    25         else
    26         {
    27             while(true)
    28             {
    29                 synchronized(Sour.lock2)
    30                 {
    31                     System.out.println("else---------lock2-------");
    32                     synchronized(Sour.lock1)
    33                     {
    34                         System.out.println("else-------lock1------");
    35                     }
    36                 }
    37             }
    38         }
    39     }
    40 }
    41 class Sour
    42 {
    43     public static final  Object lock1=new Object();
    44     public static final  Object lock2=new Object();
    45 }
    46 public class DeadLockDemo
    47 {
    48     public static void main(String args[])
    49     {
    50         Demo d1=new Demo(true);
    51         Demo d2=new Demo(false);
    52         Thread t1=new Thread(d1);
    53         Thread t2=new Thread(d2);
    54         t1.start();
    55         t2.start();
    56     }
    57 }

    死锁代码简单实例二:

     1 class Demo implements Runnable
     2 {
     3     boolean flag;
     4     public Demo(){}
     5     public Demo(boolean flag)
     6     {
     7         this.flag=flag;
     8     }
     9     public void run()
    10     {
    11         if(flag)
    12         {
    13             while(true)
    14             {
    15                 synchronized(Sour.lock1)
    16                 {
    17                     System.out.println("if---------lock1-------");
    18                     synchronized(Sour.lock2)
    19                     {
    20                         System.out.println("if-------lock2------");
    21                     }
    22                 }
    23             }
    24         }
    25         else
    26         {
    27             while(true)
    28             {
    29                 synchronized(Sour.lock2)
    30                 {
    31                     System.out.println("else---------lock2-------");
    32                     synchronized(Sour.lock1)
    33                     {
    34                         System.out.println("else-------lock1------");
    35                     }
    36                 }
    37             }
    38         }
    39     }
    40 }
    41 class Sour
    42 {
    43     public static final  Object lock1=new Object();
    44     public static final  Object lock2=new Object();
    45 }
    46 public class DeadLockDemo
    47 {
    48     public static void main(String args[])
    49     {
    50         Demo d1=new Demo();
    51         d1.flag=false;
    52         //Demo d2=new Demo(false);
    53         Thread t1=new Thread(d1);
    54         Thread t2=new Thread(d1);
    55         
    56         t1.start();
    57         try
    58         {
    59             Thread.sleep(10);
    60         }
    61         catch (InterruptedException e)
    62         {
    63         }
    64         d1.flag=true;
    65         t2.start();
    66     }
    67 }

    可以观察发现两个代码基本相同,只是主函数中的方法略有不同,其中,第一个代码有99.9%的几率在第三行就锁上;第二个代码要到几百行才能锁上,甚至有时候锁不上。

    第一种方法创建了两个实现了Runnable的接口对象,但是不影响结果;和第二个相比,第一个方法排除了不确定因素,是验证死锁程序的有效方法。

  • 相关阅读:
    iOS加载动态图的两种方法
    python初探
    博客园封笔
    office的分栏技巧
    关于排序...
    LaTex 学习笔记
    vim 学习笔记
    iOS 编程学习笔记之Foundation框架
    数论
    扫描线概览
  • 原文地址:https://www.cnblogs.com/kuangdaoyizhimei/p/4004121.html
Copyright © 2011-2022 走看看