简单的死锁示例

Roe*_*ler 88 language-agnostic multithreading deadlock

我想向新手解释线程死锁.我见过许多死锁的例子,有些使用代码,有些使用插图(比如着名的4辆汽车).还有像The Dining Philosophers这样经典的容易陷入僵局的问题,但这些问题可能过于复杂,无法让真正的新手完全掌握.

我正在寻找最简单的代码示例来说明死锁是什么.这个例子应该:

  1. 关联到一个有意义的"真实"编程场景
  2. 非常简短,简单直接

您有什么推荐的吗?

小智 134

也许是简单的银行情况.

class Account {
  double balance;

  void withdraw(double amount){
     balance -= amount;
  } 

  void deposit(double amount){
     balance += amount;
  } 

   void transfer(Account from, Account to, double amount){
        sync(from);
        sync(to);

        from.withdraw(amount);
        to.deposit(amount);

        release(to);
        release(from);
    }

}
Run Code Online (Sandbox Code Playgroud)

显然,如果有两个线程试图同时运行transfer(a,b)和transfer(b,a),那么就会发生死锁,因为它们试图以相反的顺序获取资源.

此代码也非常适合查看死锁的解决方案.希望这可以帮助!

  • 这个问题的@Jacky解决方案由Will Hartung在这里发布:http://stackoverflow.com/questions/13326861/avoid-deadlock-example/13326948#comment34617396_13326948 (2认同)
  • 我对你的语法感到困惑.什么是sync()方法?我知道如果同步(来自); ...释放(来自); 被synchronized(from)替换为{...} (2认同)
  • https://www.javaworld.com/article/2075692/java-concurrency/avoid-synchronization-deadlocks.html (Brian Goetz) 解释了此问题的解决方案。 (2认同)

Nic*_*kis 57

让大自然解释僵局,

僵局:青蛙与蛇

"我很想见到他们分道扬,,但我已经筋疲力尽了,"摄影师说道. "青蛙一直试图 把蛇拉下来,但是蛇 不会松开".

在此输入图像描述

  • 可爱,但没有解释编程上下文中如何发生死锁. (56认同)
  • 这怎么可能是CUTE?有毒的蛇和青蛙正在互相吃掉它们的可怕! (13认同)

Kyl*_*ndo 53

这是台湾某大学计算机科学系的代码示例,展示了一个带资源锁定的简单java示例.这与我的"现实生活"非常相关.代码如下:

/**
 * Adapted from The Java Tutorial
 * Second Edition by Campione, M. and
 * Walrath, K.Addison-Wesley 1998
 */

/**
 * This is a demonstration of how NOT to write multi-threaded programs.
 * It is a program that purposely causes deadlock between two threads that
 * are both trying to acquire locks for the same two resources.
 * To avoid this sort of deadlock when locking multiple resources, all threads
 * should always acquire their locks in the same order.
 **/
public class Deadlock {
  public static void main(String[] args){
    //These are the two resource objects 
    //we'll try to get locks for
    final Object resource1 = "resource1";
    final Object resource2 = "resource2";
    //Here's the first thread.
    //It tries to lock resource1 then resource2
    Thread t1 = new Thread() {
      public void run() {
        //Lock resource 1
        synchronized(resource1){
          System.out.println("Thread 1: locked resource 1");
          //Pause for a bit, simulating some file I/O or 
          //something. Basically, we just want to give the 
          //other thread a chance to run. Threads and deadlock
          //are asynchronous things, but we're trying to force 
          //deadlock to happen here...
          try{ 
            Thread.sleep(50); 
          } catch (InterruptedException e) {}

          //Now wait 'till we can get a lock on resource 2
          synchronized(resource2){
            System.out.println("Thread 1: locked resource 2");
          }
        }
      }
    };

    //Here's the second thread.  
    //It tries to lock resource2 then resource1
    Thread t2 = new Thread(){
      public void run(){
        //This thread locks resource 2 right away
        synchronized(resource2){
          System.out.println("Thread 2: locked resource 2");
          //Then it pauses, for the same reason as the first 
          //thread does
          try{
            Thread.sleep(50); 
          } catch (InterruptedException e){}

          //Then it tries to lock resource1.  
          //But wait!  Thread 1 locked resource1, and 
          //won't release it till it gets a lock on resource2.  
          //This thread holds the lock on resource2, and won't
          //release it till it gets resource1.  
          //We're at an impasse. Neither thread can run, 
          //and the program freezes up.
          synchronized(resource1){
            System.out.println("Thread 2: locked resource 1");
          }
        }
      }
    };

    //Start the two threads. 
    //If all goes as planned, deadlock will occur, 
    //and the program will never exit.
    t1.start(); 
    t2.start();
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为很好的例子.谢谢. (7认同)
  • 问题是这并不是一个真正的“现实生活”例子。它是关于“资源 1”和“资源 2”,将其与实际编程问题实际联系起来会很好(我的意思是,在实践中直接可用,参考问题域等) (2认同)

Ash*_*sia 14

如果两个或多个线程都调用method1()和method2(),则很有可能发生死锁,因为如果线程1在执行method1()时获取String对象的锁定,并且线程2在执行method2时获取对Integer对象的锁定()两者将等待彼此释放对Integer和String的锁定以继续进行,这将永远不会发生.

public void method1() {
    synchronized (String.class) {
        System.out.println("Acquired lock on String.class object");

        synchronized (Integer.class) {
            System.out.println("Acquired lock on Integer.class object");
        }
    }
}

public void method2() {
    synchronized (Integer.class) {
        System.out.println("Acquired lock on Integer.class object");

        synchronized (String.class) {
            System.out.println("Acquired lock on String.class object");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Hem*_*nth 13

我遇到的一个简单的死锁示例.

public class SimpleDeadLock {
   public static Object l1 = new Object();
   public static Object l2 = new Object();
   private int index;
   public static void main(String[] a) {
      Thread t1 = new Thread1();
      Thread t2 = new Thread2();
      t1.start();
      t2.start();
   }
   private static class Thread1 extends Thread {
      public void run() {
         synchronized (l1) {
            System.out.println("Thread 1: Holding lock 1...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock 2...");
            synchronized (l2) {
               System.out.println("Thread 2: Holding lock 1 & 2...");
            }
         }
      }
   }
   private static class Thread2 extends Thread {
      public void run() {
         synchronized (l2) {
            System.out.println("Thread 2: Holding lock 2...");
            try { Thread.sleep(10); }
            catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock 1...");
            synchronized (l1) {
               System.out.println("Thread 2: Holding lock 2 & 1...");
            }
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)


Phi*_*gan 6

这是C++ 11中的一个简单示例.

#include <mutex>    // mutex
#include <iostream> // cout 
#include <cstdio>   // getchar
#include <thread>   // this_thread, yield
#include <future>   // async
#include <chrono>   // seconds

using namespace std;
mutex _m1;
mutex _m2;

// Deadlock will occur because func12 and func21 acquires the two locks in reverse order

void func12()
{
    unique_lock<mutex> l1(_m1);
    this_thread::yield(); // hint to reschedule
    this_thread::sleep_for( chrono::seconds(1) );
    unique_lock<mutex> l2(_m2 );
}

void func21()
{
    unique_lock<mutex> l2(_m2);
    this_thread::yield(); // hint to reschedule
    this_thread::sleep_for( chrono::seconds(1) );
    unique_lock<mutex> l1(_m1);
}

int main( int argc, char* argv[] )
{
    async(func12);
    func21();
    cout << "All done!"; // this won't be executed because of deadlock
    getchar();
}
Run Code Online (Sandbox Code Playgroud)


djn*_*jna 5

请看我对这个问题的回答.每当两个线程需要获取两个不同的资源,并以不同的顺序执行此操作时,您可以获得死锁.

  • 我真的没有看到重复这里的另一个答案的信息.我认为如果您认为这个答案可以改进,您可以自由编辑. (2认同)