zoukankan      html  css  js  c++  java
  • java多线程--死锁问题

      有这样一个场景:一个中国人和一个外国人在一起吃饭,美国人拿了中国人的筷子,中国人拿了美国人的刀叉,两个人开始争执不休:

    中国人:“你先给我筷子,我再给你刀叉!”

    美国人:“你先给我刀叉,我再给你筷子!”

    ...........

      结果可想而知,两个人都吃不到饭。这个例子中的中国人和美国人相当于不同的线程,筷子和刀叉就相当于锁。两个线程在运行时都在等待对方的锁,这样便造成了程序的停滞,这种现象称为死锁。

    一、死锁的定义

         多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力。然而,并发执行也带来了新的问题——死锁。所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。

         所谓死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。

    二、死锁产生的原因

    1. 系统资源的竞争
    2. 进程推进顺序非法进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。
    3. 信号量使用不当也会造成死锁。

    三、java 死锁产生的四个必要条件:

    • 1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
    • 2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
    • 3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
    • 4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
     1 @SpringBootTest
     2 //DeadLockThread,实现Runnable接口
     3 class DeadLockThread implements Runnable {
     4     //定义Object类型的chopsticks锁对象
     5     static Object chopsticks = new Object();
     6     //定义Object类型的knifeAndFork锁对象
     7     static Object knifeAndFork = new Object();
     8     //定义Object类型的变量flag
     9     private boolean flag;
    10     //定义有参的构造方法
    11     DeadLockThread(boolean flag) {
    12         this.flag = flag;
    13     }
    14 
    15     //实现接口中的run()方法
    16     public void run() {
    17         if (flag) {
    18             while (true) {
    19                 //chopsticks锁对象上的同步代码块
    20                 synchronized (chopsticks) {
    21                     System.out.println(Thread.currentThread().getName() + "--if--chopsticks");
    22                     //knifeAndFork锁对象上的同步代码块
    23                     synchronized (knifeAndFork) {
    24                         System.out.println(Thread.currentThread().getName() + "--if--knifeAndFork");
    25                     }
    26                 }
    27             }
    28         } else {
    29             while (true) {
    30                 //knifeAndFork锁对象上的同步代码块
    31                 synchronized (knifeAndFork) {
    32                     System.out.println(Thread.currentThread().getName() + "--else--knifeAndFork");
    33                     //chopsticks锁对象上的同步代码块
    34                     synchronized (chopsticks) {
    35                         System.out.println(Thread.currentThread().getName() + "--else--chopsticks");
    36                     }
    37                 }
    38             }
    39         }
    40     }
    41 }
    42 public class Example {
    43     public static void main(String[] args) {
    44         //创建两个DeadLockThread对象
    45         DeadLockThread d1 = new DeadLockThread(true);
    46         DeadLockThread d2 = new DeadLockThread(false);
    47         //创建并开启两个线程
    48         new Thread(d1,"Chinese").start();
    49         new Thread(d2,"American").start();
    50     }
    51  }

    运行结果:

       创建了Chinese和American两个线程,分别执行了run()方法中if和else代码块中的同步代码块。Chinese线程拥有chopsticks锁,只有获得knifeAndFork锁才能执行完毕,而American拥有knifeAndFork锁,只有获得chopsticks锁才能执行完毕,两个线程都需要对方所占用的锁,但是都无法释放自己所拥有的锁,于是两个线程都处于了挂起状态,从而造成了死锁。

    四、死锁的解决方法

    1. 加锁顺序(线程按顺序加锁)
    2. 加锁时限(线程尝试获取锁的时候加上时间,超过时间则放弃对该锁的请求,并释放自己占有的锁)
    3. 死锁检测

      说实话避免死锁还得再自己写代码的时候注意一下.这里引用别人的解决方法,不过我对于这些解决方法不是太懂,讲的太含糊没有具体的实例.

  • 相关阅读:
    [leetcode]Interleaving String
    [leetcode]Scramble String
    [leetcode]Divide Two Integers
    [leetcode]Implement strStr()
    python3中用HTMLTestRunner.py报ImportError: No module named 'StringIO'如何解决
    GitHub新手快速入门日常操作流程
    smtplib.SMTPDataError: (554, 'DT:SPM 126 smtp5错误解决办法
    wamp中修改后mysq数据库l闪退无法登陆解决办法
    运行python代码报错UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 91: ordinal not in range(128)的解决办法
    测试人员如何搭建Selenium-Grid2环境(参考Java)
  • 原文地址:https://www.cnblogs.com/wx60079/p/13361482.html
Copyright © 2011-2022 走看看