ตัวอย่างการหยุดชะงักอย่างง่าย


92

ฉันอยากจะอธิบายการหยุดชะงักของเธรดให้กับมือใหม่ ฉันเคยเห็นตัวอย่างการหยุดชะงักมากมายในอดีตบางคนใช้รหัสและบางส่วนใช้ภาพประกอบ (เช่นรถ 4 คันที่มีชื่อเสียง) นอกจากนี้ยังมีปัญหาคลาสสิกที่หยุดชะงักได้ง่ายเช่นThe Dining Philosophersแต่สิ่งเหล่านี้อาจซับซ้อนเกินกว่าที่มือใหม่จริงๆจะเข้าใจได้อย่างเต็มที่

ฉันกำลังมองหาตัวอย่างโค้ดที่ง่ายที่สุดเพื่อแสดงให้เห็นว่าการหยุดชะงักคืออะไร ตัวอย่างควร:

  1. เกี่ยวข้องกับสถานการณ์การเขียนโปรแกรม "จริง" ที่สมเหตุสมผล
  2. สั้นมากเรียบง่ายและตรงไปตรงมา

คุณแนะนำเมนูใด?


ทำไมไม่ใช้รถ 4 คันที่มีชื่อเสียงเพราะมันดูตรงไปตรงมาสำหรับฉัน
vehomzzz

2
รถยนต์ทั้ง 4 คันไม่ใช่สถานการณ์ในการเขียนโปรแกรมและไม่ใช่เรื่องเล็กน้อยสำหรับมือใหม่ที่จะแก้ไขปัญหาให้เป็นรูปแบบของรถยนต์ทั้ง 4 คัน ฉันใช้มัน แต่ต้องการแสดงสถานการณ์การเขียนโปรแกรมที่เกิดการชะงักงัน
Roee Adler

นี่คือตัวอย่างhackerseve.com/creating-a-deadlock-situation-in-java
user12711663

คำตอบ:


139

อาจเป็นสถานการณ์ที่เรียบง่ายของธนาคาร

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);
    }

}

เห็นได้ชัดว่าควรมีเธรดสองเธรดที่พยายามรันการถ่ายโอน ( a, b ) และโอน ( b, a ) ในเวลาเดียวกันจากนั้นการชะงักงันจะเกิดขึ้นเนื่องจากพวกเขาพยายามที่จะได้รับทรัพยากรในลำดับย้อนกลับ

รหัสนี้เหมาะสำหรับการดูวิธีแก้ปัญหาการหยุดชะงักเช่นกัน หวังว่านี่จะช่วยได้!


1
มันจะดีมากถ้าคุณหรือคนอื่นสามารถให้วิธีแก้ปัญหานี้ได้
Jacky

2
@Jacky วิธีแก้ปัญหาสำหรับปัญหานี้โพสต์โดย Will Hartung ที่นี่: stackoverflow.com/questions/13326861/avoid-deadlock-example/…
Piotr Chojnacki

2
ฉันสับสนกับไวยากรณ์ของคุณ วิธีการซิงค์ () คืออะไร? ฉันเข้าใจว่าถ้า sync (จาก); ... release (from); ถูกแทนที่ด้วยซิงโครไนซ์ (จาก) {... }
Ellen Spertus

1
@espertus syncอาจเป็นเช่น: sync(Account & a) { a.mutex.lock(); }.
vladon

1
javaworld.com/article/2075692/java-concurrency/… (Brian Goetz) อธิบายวิธีแก้ปัญหานี้
lingareddyk

59

ให้ธรรมชาติอธิบายการหยุดชะงัก

Deadlock: กบกับงู

“ ฉันชอบที่จะเห็นพวกเขาแยกทางกัน แต่ฉันก็เหนื่อยแล้ว” ช่างภาพกล่าว "กบเป็นตลอดเวลาพยายามที่จะ ดึงงูออก แต่งูเพียง จะไม่ปล่อยให้ไป"

ป้อนคำอธิบายภาพที่นี่


59
น่ารัก แต่ไม่ได้อธิบายว่าการหยุดชะงักเกิดขึ้นได้อย่างไรในบริบทการเขียนโปรแกรม
jalf

ตกลงอย่างน้อยคุณก็ให้เหตุผลในการโหวตลง ยังไงก็คล้ายกับตัวอย่าง "รถ 4 คัน" การแสดงที่น่ารักว่าการหยุดชะงักมีลักษณะอย่างไร
Nick Dandoulakis

@Nick Dandoulakis: การนำเสนอภาพที่ยอดเยี่ยม รูปภาพอธิบายแนวคิดของการหยุดชะงัก
Rasmi Ranjan Nayak

@NickDandoulakis - ไม่ใช่ตัวอย่างรูปที่ดี imho รหัสง่ายๆจะเป็นประโยชน์ที่นี่
Erran Morad

13
สิ่งนี้ควรจะน่ารักขนาดไหน? งูพิษกบกินกันเองน่ากลัว !!!
vikkyhacks

56

นี่คือตัวอย่างโค้ดจากแผนกวิทยาการคอมพิวเตอร์ของมหาวิทยาลัยในไต้หวันที่แสดงตัวอย่าง 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();
  }
}

2
ปัญหาคือมันไม่ใช่ "ชีวิตจริง" ตัวอย่าง มันเป็นเรื่องของ "ทรัพยากร 1" และ "ทรัพยากรที่ 2" และมันจะดีจริงความสัมพันธ์นี้จะเป็นปัญหาการเขียนโปรแกรมที่เกิดขึ้นจริง (ผมหมายถึงโดยตรงสามารถใช้งานได้ในทางปฏิบัติมีการอ้างอิงถึงโดเมนปัญหา ฯลฯ )
เจ

7
ตัวอย่างที่ดีในความคิดของฉัน ขอบคุณ.
James Raitsev

ดูเหมือนว่าโค้ดนี้จะได้รับการเผยแพร่ในหนังสือสองเล่ม ... stackoverflow.com/a/11338853/112705
Dan J

15

หาก method1 () และ method2 () ทั้งสองถูกเรียกโดยเธรดสองหรือหลายเธรดมีโอกาสที่ดีที่จะเกิดการชะงักงันเนื่องจากหากเธรด 1 ได้รับการล็อกบนอ็อบเจ็กต์ String ในขณะที่ดำเนินการ method1 () และเธรด 2 ได้รับการล็อกอ็อบเจ็กต์จำนวนเต็มในขณะที่รัน method2 () ทั้งสองจะรอให้กันและกันเพื่อปลดล็อก 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");
        }
    }
}

ง่ายและรวดเร็ว ดี.
user1068352

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...");
            }
         }
      }
   }
}

ฉันชอบตัวอย่างนั้น แต่ทำไมคลาส SimpleDeadLock จึงออกจากเธรด? นั่นไม่จำเป็น
Charmin

1
นี้สวยมากเป็นสิ่งเดียวกับคำตอบนี้: stackoverflow.com/a/1385868/1310566 แล้วมันไปprivate int indexทำอะไรที่นั่น?
Simon Forsberg

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();
}

5

โปรดดูคำตอบของฉันสำหรับคำถามนี้ บรรทัดด้านล่างเมื่อใดก็ตามที่สองเธรดต้องการได้รับทรัพยากรที่แตกต่างกันสองรายการและทำตามคำสั่งที่แตกต่างกันคุณจะได้รับการชะงักงัน


2
ฉันไม่เห็นประเด็นในการทำซ้ำข้อมูลจากคำตอบอื่นที่นี่ ฉันคิดว่าถ้าคุณคิดว่าคำตอบนี้สามารถปรับปรุงได้คุณก็มีอิสระที่จะแก้ไขด้วยตัวเอง
djna

ฉันคิดว่าสถานการณ์นี้เรียกว่า "การผกผันการล็อก" ฉันรู้ว่ามันเรียกว่าการผกผันการล็อคเพราะฉันเรียกมันว่า แต่ฉันคิดว่ามันเป็นคำศัพท์ของศิลปะด้วย :-)
Steve Jessop

4

ตัวอย่างหนึ่งที่ฉันคิดได้คือสถานการณ์ตารางไฟฉายและแบตเตอรี่ ลองนึกภาพไฟฉายและแบตเตอรี่คู่หนึ่งวางอยู่บนโต๊ะ หากคุณต้องเดินไปที่โต๊ะนี้และคว้าแบตเตอรี่ในขณะที่อีกคนมีไฟฉายคุณทั้งคู่จะต้องจ้องหน้ากันอย่างเชื่องช้าในขณะที่รอว่าใครจะเป็นคนแรกที่จะวางสิ่งของของพวกเขากลับไปที่โต๊ะ นี่คือตัวอย่างของการหยุดชะงัก คุณและบุคคลนั้นกำลังรอทรัพยากร แต่ไม่มีใครสละทรัพยากรของพวกเขา

ในทำนองเดียวกันในโปรแกรมการหยุดชะงักจะเกิดขึ้นเมื่อเธรดสองชุดขึ้นไป (คุณและอีกฝ่าย) กำลังรอให้ล็อคสองตัวขึ้นไป (ไฟฉายและแบตเตอรี่) ได้รับการปลดปล่อยและสถานการณ์ในโปรแกรมเป็นเช่นนั้นการล็อคจะไม่เป็นอิสระ ( คุณทั้งคู่มีจิ๊กซอว์ชิ้นเดียว)

หากคุณรู้จัก java นี่คือวิธีที่คุณสามารถแสดงปัญหานี้:

import java.util.concurrent.locks.*;

public class Deadlock1 {

    public static class Table {

        private static Lock Flashlight = new ReentrantLock();
        private static Lock Batteries = new ReentrantLock();        

        public static void giveFlashLightAndBatteries() {
            try {
                Flashlight.lock();
                Batteries.lock();
                System.out.println("Lights on");
            } finally {
                Batteries.unlock();
                Flashlight.unlock();
            }
        }

        public static void giveBatteriesAndFlashLight() {
            try {
                Batteries.lock();
                Flashlight.lock();
                System.out.println("Lights on");
            } finally {
                Flashlight.unlock();
                Batteries.unlock();
            }
        }
    }

    public static void main(String[] args) {
        // This thread represents person one
        new Thread(new Runnable() {
            public void run() { Table.giveFlashLightAndBatteries(); }
        }).start();

        // This thread represents person two
        new Thread(new Runnable() {
            public void run() { Table.giveBatteriesAndFlashLight(); }
        }).start();
    }
}

หากคุณเรียกใช้ตัวอย่างนี้คุณจะสังเกตเห็นว่าบางครั้งสิ่งต่างๆก็ทำได้ดีและถูกต้อง แต่บางครั้งโปรแกรมของคุณก็ไม่สามารถพิมพ์อะไรได้เลย นั่นเป็นเพราะคน ๆ หนึ่งมีแบตเตอรี่ในขณะที่อีกคนมีไฟฉายซึ่งป้องกันไม่ให้พวกเขาเปิดไฟฉายทำให้เกิดการหยุดชะงัก

ตัวอย่างนี้คล้ายกับตัวอย่างที่กำหนดโดยบทเรียน java: http://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

อีกตัวอย่างหนึ่งคือตัวอย่างลูป:

public class Deadlock2 {

    public static class Loop {
        private static boolean done = false;

        public static synchronized void startLoop() throws InterruptedException {
            while(!done) {
                Thread.sleep(1000);
                System.out.println("Not done");
            }
        }

        public static synchronized void stopLoop() {
            done = true;
        }

    }

    public static void main(String[] args) {
        // This thread starts the loop
        new Thread(new Runnable() {
            public void run() {
                try {
                    Loop.startLoop();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        // This thread stops the loop
        new Thread(new Runnable() {
            public void run() {
                Loop.stopLoop();
            }
        }).start();
    }
}

ตัวอย่างนี้สามารถพิมพ์ 'ยังไม่เสร็จ' ซ้ำแล้วซ้ำอีกหรือไม่สามารถพิมพ์ 'ยังไม่เสร็จ' ได้เลย สิ่งแรกเกิดขึ้นเนื่องจากเธรดแรกได้รับการล็อกคลาสและไม่เคยเผยแพร่เพื่อป้องกันไม่ให้เธรดที่สองเข้าถึง 'stopLoop' และล่าสุดเกิดขึ้นเนื่องจากเธรดที่สองเริ่มต้นก่อนเธรดแรกทำให้ตัวแปร "done" เป็นจริงก่อนที่เธรดแรกจะทำงาน


4
public class DeadLock {
    public static void main(String[] args) throws InterruptedException {
        Thread mainThread = Thread.currentThread();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mainThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread1.start();
        thread1.join();
    }
}

3

ฉันคิดว่าปัญหา Dining Philosophers เป็นหนึ่งในตัวอย่างที่ง่ายกว่าในการแสดงการหยุดชะงักเนื่องจากข้อกำหนดการหยุดชะงัก 4 ข้อสามารถแสดงให้เห็นได้อย่างง่ายดายด้วยรูปวาด (โดยเฉพาะการรอแบบวงกลม)

ฉันคิดว่าตัวอย่างในโลกแห่งความเป็นจริงจะสร้างความสับสนให้กับมือใหม่มากขึ้นแม้ว่าฉันจะไม่สามารถนึกถึงสถานการณ์ในโลกแห่งความเป็นจริงที่ดีได้ในตอนนี้ (ฉันค่อนข้างไม่มีประสบการณ์กับการทำงานพร้อมกันในโลกแห่งความจริง)


3

ฉันเพิ่งรู้ว่าการต่อสู้ระหว่างคู่รักไม่มีอะไรนอกจากการหยุดชะงัก .. ซึ่งโดยปกติแล้วกระบวนการหนึ่งจะต้องล้มเหลวเพื่อแก้ไขแน่นอนว่ามันมีลำดับความสำคัญน้อยกว่า (บอย;))

นี่คือการเปรียบเทียบ ...

Process1: Girl (G) Process2: Boy (B)
Resource1: Sorry Resource2: ยอมรับความผิดพลาดของตัวเอง

เงื่อนไขที่จำเป็น:
1. การกีดกันซึ่งกันและกัน: G หรือ B เพียงคนเดียวเท่านั้นที่สามารถพูดขอโทษหรือยอมรับข้อผิดพลาดของตัวเองได้ในแต่ละครั้ง
2. รอสักครู่:ในแต่ละครั้งมีคนหนึ่งถือคำว่า Sorry และอีกคนยอมรับความผิดพลาดของตัวเองคนหนึ่งกำลังรอให้ยอมรับความผิดพลาดของตัวเองเพื่อปล่อยคำขอโทษและอีกคนกำลังรอให้ขอโทษเพื่อปล่อยยอมรับความผิดพลาด
3. ไม่มีใบจอง:แม้แต่พระเจ้าก็ไม่สามารถบังคับให้ B หรือ G ปล่อยขอโทษหรือยอมรับความผิดพลาดของตัวเองได้ และสมัครใจ? คุณล้อเล่นหรือเปล่า ??
4. การรอแบบวงกลม:อีกครั้งคนที่เสียใจรอให้คนอื่นยอมรับความผิดพลาดของตัวเองและคนที่ยอมรับความผิดพลาดของตัวเองต้องการให้คนอื่นพูดขอโทษก่อน มันจึงเป็นวงกลม

การหยุดชะงักจึงเกิดขึ้นเมื่อเงื่อนไขเหล่านี้มีผลในเวลาเดียวกันและนั่นก็เป็นเช่นนั้นเสมอในการต่อสู้สองสามครั้ง)

ที่มา: http://www.quora.com/Saurabh-Pandey-3/Posts/Never-ending-couple-fights-a-deadlock


3

อีกหนึ่งตัวอย่างการหยุดชะงักที่เรียบง่ายซึ่งมีทรัพยากรที่แตกต่างกันสองรายการและเธรดสองชุดที่รอกันและกันเพื่อปล่อยทรัพยากร โดยตรงจากexample.oreilly.com/jenut/Deadlock.java

 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();
  }
}

If all goes as planned, deadlock will occur, and the program will never exit.เราสามารถทำให้ตัวอย่างนี้guaranteeหยุดชะงักได้หรือไม่?
Erran Morad

นี่คือรหัสเดียวกับที่Kyle โพสต์ทำไมต้องเพิ่มคำตอบที่ซ้ำกันสามปีหลังจากคำตอบอื่น (แล้วฉันจะแสดงความคิดเห็นทำไมอีกสามปีต่อมา)
Simon Forsberg

2

การหยุดชะงักสามารถเกิดขึ้นได้ในสถานการณ์ที่ a Girl1กำลังอยากจะจีบGuy2ใครอีกคนที่จับได้Girl2และGirl2กำลังอยากจีบคนGuy1ที่โดนจับGirl1ได้ เนื่องจากเด็กหญิงทั้งสองกำลังรอการทิ้งซึ่งกันและกันสภาพที่เรียกว่าการหยุดชะงัก

class OuchTheGirls
{
    public static void main(String[] args)
    {
        final String resource1 = "Guy1";
        final String resource2 = "Guy2";

        // Girl1 tries to lock resource1 then resource2
        Thread Girl1 = new Thread(() ->
                                  {
                                      synchronized (resource1)
                                      {
                                          System.out.println("Thread 1: locked Guy1");

                                          try { Thread.sleep(100);} catch (Exception e) {}

                                          synchronized (resource2)
                                          {
                                              System.out.println("Thread 1: locked Guy2");
                                          }
                                      }
                                  });

        // Girl2 tries to lock Guy2 then Guy1
        Thread Girl2 = new Thread(() ->
                                  {
                                      synchronized (resource2)
                                      {
                                          System.out.println("Thread 2: locked Guy2");

                                          try { Thread.sleep(100);} catch (Exception e) {}

                                          synchronized (resource1)
                                          {
                                              System.out.println("Thread 2: locked Guy1");
                                          }
                                      }
                                  });


        Girl1.start();
        Girl2.start();
    }
}

ไม่ใช่แนวทางปฏิบัติที่ดีในการล็อกคลาส String หรือ wrapper เนื่องจากวิธีการจัดการสตริงภายในและอ็อบเจ็กต์ wrapper ใน java การอ้างอิงหลายรายการจะชี้ไปที่วัตถุเดียวกันภายใน ใช้คลาส Object ได้ดีกว่าถ้าคุณไม่มีวัตถุที่กำหนดเอง
Lokesh

1

ปัญหาผู้ผลิต - ผู้บริโภคร่วมกับปัญหาของนักปรัชญาการรับประทานอาหารนั้นอาจจะง่ายอย่างที่คิด มันมีรหัสเทียมบางอย่างที่แสดงให้เห็นเช่นกัน หากสิ่งเหล่านี้ซับซ้อนเกินไปสำหรับมือใหม่ก็ควรพยายามเข้าใจให้มากขึ้น


1

ไปที่สถานการณ์ที่เป็นไปได้อย่างง่ายซึ่งอาจเกิดการหยุดชะงักเมื่อแนะนำแนวคิดให้นักเรียนของคุณ สิ่งนี้จะเกี่ยวข้องกับเธรดอย่างน้อยสองเธรดและทรัพยากรอย่างน้อยสองรายการ (ฉันคิดว่า) เป้าหมายคือการสร้างสถานการณ์ที่เธรดแรกมีการล็อกทรัพยากรหนึ่งและกำลังรอให้การล็อกทรัพยากรสองถูกปลดล็อกในขณะเดียวกันเธรดที่สองจะล็อกทรัพยากรสองและกำลังรอ การล็อกทรัพยากรหนึ่งที่จะปล่อย

ไม่สำคัญจริงๆว่าทรัพยากรพื้นฐานคืออะไร เพื่อความเรียบง่ายคุณสามารถกำหนดให้เป็นไฟล์คู่ที่ทั้งสองเธรดสามารถเขียนถึงได้

แก้ไข: ถือว่าไม่มีการสื่อสารระหว่างกระบวนการอื่นนอกเหนือจากการล็อกที่เก็บไว้


1

ฉันพบว่ายากที่จะเข้าใจเมื่ออ่านปัญหาของนักปรัชญาการรับประทานอาหารการหยุดชะงักของ IMHO เกี่ยวข้องกับการจัดสรรทรัพยากรจริงๆ ต้องการแบ่งปันตัวอย่างง่าย ๆ ที่ 2 พยาบาลต้องต่อสู้เพื่อ 3 อุปกรณ์เพื่อให้งานสำเร็จ แม้ว่ามันจะเขียนด้วย java เมธอด lock () อย่างง่ายถูกสร้างขึ้นเพื่อจำลองว่าการหยุดชะงักเกิดขึ้นได้อย่างไรดังนั้นจึงสามารถใช้กับภาษาโปรแกรมอื่น ๆ ได้เช่นกัน http://www.justexample.com/wp/example-of-deadlock/


1

ตัวอย่างง่ายๆจากhttps://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

public class Deadlock {

public static void printMessage(String message) {

    System.out.println(String.format("%s %s ", Thread.currentThread().getName(), message));

}

private static class Friend {

    private String name;

    public Friend(String name) {
        this.name = name;
    }

    public void bow(Friend friend) {

        printMessage("Acquiring lock on " + this.name);

        synchronized(this) {
            printMessage("Acquired lock on " + this.name);
            printMessage(name + " bows " + friend.name);
            friend.bowBack(this);
        }

    }

    public void bowBack(Friend friend) {

        printMessage("Acquiring lock on " + this.name);

        synchronized (this) {
            printMessage("Acquired lock on " + this.name);
            printMessage(friend.name + " bows back");
        }

    }

}

public static void main(String[] args) throws InterruptedException {

    Friend one = new Friend("one");
    Friend two = new Friend("two");

    new Thread(new Runnable() {
        @Override
        public void run() {
            one.bow(two);
        }
    }).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            two.bow(one);
        }
    }).start();
}

}

เอาท์พุต:

Thread-0 Acquiring lock on one 
Thread-1 Acquiring lock on two 
Thread-0 Acquired lock on one 
Thread-1 Acquired lock on two 
Thread-1 two bows one 
Thread-0 one bows two 
Thread-1 Acquiring lock on one 
Thread-0 Acquiring lock on two 

การถ่ายโอนข้อมูลด้าย:

2016-03-14 12:20:09
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.74-b02 mixed mode):

"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x00007f472400a000 nid=0x3783 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-1" #12 prio=5 os_prio=0 tid=0x00007f472420d800 nid=0x37a3 waiting for monitor entry [0x00007f46e89a5000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$2.run(ThreadJoin.java:141)
    at java.lang.Thread.run(Thread.java:745)

"Thread-0" #11 prio=5 os_prio=0 tid=0x00007f472420b800 nid=0x37a2 waiting for monitor entry [0x00007f46e8aa6000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$1.run(ThreadJoin.java:134)
    at java.lang.Thread.run(Thread.java:745)

"Monitor Ctrl-Break" #10 daemon prio=5 os_prio=0 tid=0x00007f4724211000 nid=0x37a1 runnable [0x00007f46e8def000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
    at java.net.SocketInputStream.read(SocketInputStream.java:170)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
    - locked <0x000000076d20afb8> (a java.io.InputStreamReader)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.fill(BufferedReader.java:161)
    at java.io.BufferedReader.readLine(BufferedReader.java:324)
    - locked <0x000000076d20afb8> (a java.io.InputStreamReader)
    at java.io.BufferedReader.readLine(BufferedReader.java:389)
    at com.intellij.rt.execution.application.AppMain$1.run(AppMain.java:93)
    at java.lang.Thread.run(Thread.java:745)

"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00007f47240c9800 nid=0x3794 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread3" #8 daemon prio=9 os_prio=0 tid=0x00007f47240c6800 nid=0x3793 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread2" #7 daemon prio=9 os_prio=0 tid=0x00007f47240c4000 nid=0x3792 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #6 daemon prio=9 os_prio=0 tid=0x00007f47240c2800 nid=0x3791 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 tid=0x00007f47240bf800 nid=0x3790 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f47240be000 nid=0x378f waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f472408c000 nid=0x378e in Object.wait() [0x00007f46e98c5000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076cf88ee0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x000000076cf88ee0> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f4724087800 nid=0x378d in Object.wait() [0x00007f46e99c6000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x000000076cf86b50> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:502)
    at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    - locked <0x000000076cf86b50> (a java.lang.ref.Reference$Lock)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"VM Thread" os_prio=0 tid=0x00007f4724080000 nid=0x378c runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f472401f000 nid=0x3784 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f4724021000 nid=0x3785 runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f4724022800 nid=0x3786 runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f4724024800 nid=0x3787 runnable 

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00007f4724026000 nid=0x3788 runnable 

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00007f4724028000 nid=0x3789 runnable 

"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00007f4724029800 nid=0x378a runnable 

"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00007f472402b800 nid=0x378b runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007f47240cc800 nid=0x3795 waiting on condition 

JNI global references: 16


Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f46dc003f08 (object 0x000000076d0583a0, a com.anantha.algorithms.ThreadJoin$Friend),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f46dc006008 (object 0x000000076d0583e0, a com.anantha.algorithms.ThreadJoin$Friend),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$2.run(ThreadJoin.java:141)
    at java.lang.Thread.run(Thread.java:745)
"Thread-0":
    at com.anantha.algorithms.ThreadJoin$Friend.bowBack(ThreadJoin.java:102)
    - waiting to lock <0x000000076d0583e0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$Friend.bow(ThreadJoin.java:92)
    - locked <0x000000076d0583a0> (a com.anantha.algorithms.ThreadJoin$Friend)
    at com.anantha.algorithms.ThreadJoin$1.run(ThreadJoin.java:134)
    at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock.

Heap
 PSYoungGen      total 74752K, used 9032K [0x000000076cf80000, 0x0000000772280000, 0x00000007c0000000)
  eden space 64512K, 14% used [0x000000076cf80000,0x000000076d8520e8,0x0000000770e80000)
  from space 10240K, 0% used [0x0000000771880000,0x0000000771880000,0x0000000772280000)
  to   space 10240K, 0% used [0x0000000770e80000,0x0000000770e80000,0x0000000771880000)
 ParOldGen       total 171008K, used 0K [0x00000006c6e00000, 0x00000006d1500000, 0x000000076cf80000)
  object space 171008K, 0% used [0x00000006c6e00000,0x00000006c6e00000,0x00000006d1500000)
 Metaspace       used 3183K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 352K, capacity 388K, committed 512K, reserved 1048576K

1

นี่คือการชะงักงันง่ายๆใน Java เราต้องการทรัพยากรสองอย่างสำหรับการสาธิตการหยุดชะงัก ในตัวอย่างด้านล่างทรัพยากรหนึ่งคือการล็อกคลาส (ผ่านวิธีการซิงค์) และอีกทรัพยากรหนึ่งเป็นจำนวนเต็ม 'i'

public class DeadLock {

    static int i;
    static int k;

    public static synchronized void m1(){
        System.out.println(Thread.currentThread().getName()+" executing m1. Value of i="+i);

        if(k>0){i++;}

        while(i==0){
            System.out.println(Thread.currentThread().getName()+" waiting in m1 for i to be > 0. Value of i="+i);
            try { Thread.sleep(10000);} catch (InterruptedException e) { e.printStackTrace(); }
        }
    }

    public static void main(String[] args) {

        Thread t1 = new Thread("t1") {
            public void run() {
                m1();
            }
        };

        Thread t2 = new Thread("t2") {
            public void run() {
                try { Thread.sleep(100);} catch (InterruptedException e) { e.printStackTrace(); }
                k++;
                m1();
            }
        };

        t1.start();
        t2.start();
    }
}

1
public class DeadLock {

    public static void main(String[] args) {
        Object resource1 = new Object();
        Object resource2 = new Object();
        SharedObject s = new SharedObject(resource1, resource2);
        TestThread11 t1 = new TestThread11(s);
        TestThread22 t2 = new TestThread22(s);
        t1.start();
        t2.start();
    }

}

class SharedObject {
    Object o1, o2;
    SharedObject(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }
    void m1() {
        synchronized(o1) {
            System.out.println("locked on o1 from m1()");
            synchronized(o2) { 
                System.out.println("locked on o2 from m1()");
            }
        }
    }
    void m2() {
        synchronized(o2) {
            System.out.println("locked on o2 from m2()");
            synchronized(o1) { 
                System.out.println("locked on o1 from m2()");
            }
        }
    }
}

class TestThread11 extends Thread {
    SharedObject s;
    TestThread11(SharedObject s) {
        this.s = s;
    }
    public void run() {
        s.m1();
    }
}

class TestThread22 extends Thread {
    SharedObject s;
    TestThread22(SharedObject s) {
        this.s = s;
    }
    public void run() {
        s.m2();
    }
}

1
คุณช่วยเพิ่มข้อความเพื่ออธิบายคำตอบของคุณได้ไหม
Kmeixner

1

นี่คือการหยุดชะงักง่ายๆใน C #

void UpdateLabel(string text) {
   lock(this) {
      if(MyLabel.InvokeNeeded) {
        IAsyncResult res =  MyLable.BeginInvoke(delegate() {
             MyLable.Text = text;
            });
         MyLabel.EndInvoke(res);
        } else {
             MyLable.Text = text;
        }
    }
}

หากวันหนึ่งคุณเรียกสิ่งนี้จากเธรด GUI และอีกเธรดหนึ่งเรียกมันเช่นกันคุณอาจชะงักงัน เธรดอื่นเข้าสู่ EndInvoke รอให้เธรด GUI ดำเนินการมอบหมายขณะที่ล็อก เธรด GUI บล็อกบนล็อกเดียวกันที่รอให้เธรดอื่นคลายออกซึ่งจะไม่เป็นเพราะเธรด GUI จะไม่พร้อมใช้งานเพื่อดำเนินการมอบหมายเธรดอื่นที่รออยู่ (แน่นอนว่าการล็อคที่นี่ไม่จำเป็นอย่างยิ่ง - หรืออาจจะเป็น EndInvoke แต่ในสถานการณ์ที่ซับซ้อนกว่าเล็กน้อยผู้โทรอาจได้รับการล็อกด้วยเหตุผลอื่น ๆ ซึ่งส่งผลให้เกิดการหยุดชะงักเดียวกัน)


0
package test.concurrent;
public class DeadLockTest {
   private static long sleepMillis;
   private final Object lock1 = new Object();
   private final Object lock2 = new Object();

   public static void main(String[] args) {
       sleepMillis = Long.parseLong(args[0]);
       DeadLockTest test = new DeadLockTest();
       test.doTest();
   }

   private void doTest() {
       Thread t1 = new Thread(new Runnable() {
           public void run() {
               lock12();
           }
       });
       Thread t2 = new Thread(new Runnable() {
           public void run() {
               lock21();
           }
       });
       t1.start();
       t2.start();
   }

   private void lock12() {
       synchronized (lock1) {
           sleep();
           synchronized (lock2) {
               sleep();
           }
       }
   }

   private void lock21() {
       synchronized (lock2) {
           sleep();
           synchronized (lock1) {
               sleep();
           }
       }
   }

   private void sleep() {
       try {
           Thread.sleep(sleepMillis);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }
}
To run the deadlock test with sleep time 1 millisecond:
java -cp . test.concurrent.DeadLockTest 1

0
public class DeadlockProg {

    /**
     * @Gowtham Chitimi Reddy IIT(BHU);
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        final Object ob1 = new Object();
        final Object ob2 = new Object();
        Thread t1 = new Thread(){
            public void run(){
                synchronized(ob1){
                    try{
                        Thread.sleep(100);
                    }
                    catch(InterruptedException e){
                        System.out.println("Error catched");
                    }
                    synchronized(ob2){

                    }
                }

            }
        };
        Thread t2 = new Thread(){
            public void run(){
                synchronized(ob2){
                    try{
                        Thread.sleep(100);
                    }
                    catch(InterruptedException e){
                        System.out.println("Error catched");
                    }
                    synchronized(ob1){                      
                    }
                }               
            }
        };
        t1.start();
        t2.start();
    }

}

0
package ForkBlur;

public class DeadLockTest {
  public static void main(String args[]) {

    final DeadLockTest t1 = new DeadLockTest();
    final DeadLockTest t2 = new DeadLockTest();

    Runnable r1 = new Runnable() {

        @Override
        public void run() {
            try {

                synchronized (t1) {
                    System.out
                            .println("r1 has locked t1, now going to sleep");
                    Thread.sleep(100);
                    System.out
                            .println("r1 has awake , now going to aquire lock for t2");
                    synchronized (t2) {
                        Thread.sleep(100);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    };

    Runnable r2 = new Runnable() {

        @Override
        public void run() {
            try {

                synchronized (t2) {
                    System.out
                            .println("r2 has aquire the lock of t2 now going to sleep");
                    Thread.sleep(100);
                    System.out
                            .println("r2 is awake , now going to aquire the lock from t1");
                    synchronized (t1) {
                        Thread.sleep(100);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    };

    new Thread(r1).start();
    new Thread(r2).start();
  }
}

0

ฉันได้สร้างตัวอย่าง DeadLock ที่ใช้งานง่ายเป็นพิเศษ: -

package com.thread.deadlock;

public class ThreadDeadLockClient {

    public static void main(String[] args) {
        ThreadDeadLockObject1 threadDeadLockA = new ThreadDeadLockObject1("threadDeadLockA");
        ThreadDeadLockObject2 threadDeadLockB = new ThreadDeadLockObject2("threadDeadLockB");

        new Thread(new Runnable() {

            @Override
            public void run() {
                threadDeadLockA.methodA(threadDeadLockB);

            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                threadDeadLockB.methodB(threadDeadLockA);

            }
        }).start();
    }
}

package com.thread.deadlock;

public class ThreadDeadLockObject1 {

    private String name;

    ThreadDeadLockObject1(String name){
        this.name = name;
    }

    public  synchronized void methodA(ThreadDeadLockObject2 threadDeadLockObject2) {
        System.out.println("In MethodA "+" Current Object--> "+this.getName()+" Object passed as parameter--> "+threadDeadLockObject2.getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        threadDeadLockObject2.methodB(this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }   
}

package com.thread.deadlock;

public class ThreadDeadLockObject2 {

    private String name;

    ThreadDeadLockObject2(String name){
        this.name = name;
    }

    public  synchronized void methodB(ThreadDeadLockObject1 threadDeadLockObject1) {
        System.out.println("In MethodB "+" Current Object--> "+this.getName()+" Object passed as parameter--> "+threadDeadLockObject1.getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        threadDeadLockObject1.methodA(this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

ในตัวอย่างข้างต้น 2 เธรดกำลังเรียกใช้เมธอดที่ซิงโครไนซ์ของวัตถุสองชิ้นที่แตกต่างกัน เมธอดที่ซิงโครไนซ์ A ถูกเรียกโดยอ็อบเจ็กต์ threadDeadLockA และซิงโครไนซ์ methodB ถูกเรียกโดยอ็อบเจ็กต์ threadDeadLockB ใน methodA การอ้างอิงของ threadDeadLockB จะถูกส่งผ่านและใน methodB จะส่งการอ้างอิงของ threadDeadLockA ตอนนี้แต่ละเธรดจะพยายามล็อควัตถุอื่น ในวิธีการเธรดที่ถือล็อกบน threadDeadLockA กำลังพยายามล็อกอ็อบเจ็กต์ threadDeadLockB และในทำนองเดียวกันใน methodB เธรดที่กำลังล็อก threadDeadLockB กำลังพยายามล็อก threadDeadLockA ดังนั้นทั้งสองเธรดจะรอตลอดไปเพื่อสร้างการหยุดชะงัก


0

ให้ฉันอธิบายให้ชัดเจนยิ่งขึ้นโดยใช้ตัวอย่างที่มีมากกว่า2เธรด

ให้เราบอกว่าคุณมี n เธรดแต่ละตัวล็อค L1, L2, ... , Ln ตามลำดับ ตอนนี้สมมติว่าเริ่มจากเธรด 1 แต่ละเธรดพยายามที่จะได้รับการล็อกเธรดเพื่อนบ้าน ดังนั้นเธรด 1 จึงถูกบล็อกเนื่องจากพยายามรับ L2 (เนื่องจาก L2 เป็นของเธรด 2) เธรด 2 จึงถูกบล็อกสำหรับ L3 และอื่น ๆ เธรด n ถูกบล็อกสำหรับ L1 นี่คือการชะงักงันเนื่องจากไม่มีเธรดสามารถดำเนินการได้

class ImportantWork{
   synchronized void callAnother(){     
   }
   synchronized void call(ImportantWork work) throws InterruptedException{
     Thread.sleep(100);
     work.callAnother();
   }
}
class Task implements Runnable{
  ImportantWork myWork, otherWork;
  public void run(){
    try {
      myWork.call(otherWork);
    } catch (InterruptedException e) {      
    }
  }
}
class DeadlockTest{
  public static void main(String args[]){
    ImportantWork work1=new ImportantWork();
    ImportantWork work2=new ImportantWork();
    ImportantWork work3=new ImportantWork();
    Task task1=new Task(); 
    task1.myWork=work1;
    task1.otherWork=work2;

    Task task2=new Task(); 
    task2.myWork=work2;
    task2.otherWork=work3;

    Task task3=new Task(); 
    task3.myWork=work3;
    task3.otherWork=work1;

    new Thread(task1).start();
    new Thread(task2).start();
    new Thread(task3).start();
  }
}

ในตัวอย่างข้างต้นคุณจะเห็นว่ามีสามเธรดที่ถือRunnables task1, task2 และ task3 ก่อนคำสั่งsleep(100)เธรดจะได้รับล็อกอ็อบเจ็กต์งานทั้งสามเมื่อเข้าสู่call()เมธอด (เนื่องจากมีอยู่synchronized) แต่ทันทีที่พวกเขาพยายามcallAnother()ต่อวัตถุของเธรดเพื่อนบ้านของพวกเขาพวกมันก็ถูกบล็อกนำไปสู่การชะงักงันเนื่องจากล็อควัตถุเหล่านั้นได้ถูกยึดไป


0
CountDownLatch countDownLatch = new CountDownLatch(1);
ExecutorService executorService = ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(() -> {
    Future<?> future = executorService.submit(() -> {
        System.out.println("generated task");
    });
    countDownLatch.countDown();
    try {
        future.get();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
         e.printStackTrace();
    }
});


countDownLatch.await();
executorService.shutdown();

0

วิธีส่อเสียดในการหยุดชะงักด้วยเธรดเดียวคือพยายามล็อค mutex เดียวกัน (ไม่เรียกซ้ำ) สองครั้ง นี่อาจไม่ใช่ตัวอย่างง่ายๆที่คุณกำลังมองหา แต่ก็เพียงพอแล้วที่ฉันพบกรณีดังกล่าวแล้ว

#include <mutex>
#include <iostream>

int main()
{
  std::mutex m;
  m.lock();
  m.lock();
  std::cout << "Expect never to get here because of a deadlock!";
}

0

นี่คือตัวอย่างโดยละเอียดของฉันสำหรับการหยุดชะงักหลังจากใช้เวลามากมาย หวังว่าจะช่วยได้ :)

package deadlock;

public class DeadlockApp {

    String s1 = "hello";
    String s2 = "world";

    Thread th1 = new Thread() {
        public void run() {
            System.out.println("Thread th1 has started");
            synchronized (s1) { //A lock is created internally (holds access of s1), lock will be released or unlocked for s1, only when it exits the block Line #23
                System.out.println("Executing first synchronized block of th1!");
                try {
                    Thread.sleep(1000);
                } catch(InterruptedException ex) {
                    System.out.println("Exception is caught in th1");
                }
                System.out.println("Waiting for the lock to be released from parrallel thread th1");
                synchronized (s2) { //As another has runned parallely Line #32, lock has been created for s2
                    System.out.println(s1 + s2);
                }

            }
            System.out.println("Thread th1 has executed");
        }
    };


    Thread th2 = new Thread() {
        public void run() {
            System.out.println("Thread th2 has started");
            synchronized (s2) { //A lock is created internally (holds access of s2), lock will be released or unlocked for s2, only when it exits the block Line #44
                System.out.println("Executing first synchronized block of th2!");
                try {
                    Thread.sleep(1000);
                } catch(InterruptedException ex) {
                    System.out.println("Exception is caught in th2");
                }
                System.out.println("Waiting for the lock to be released from parrallel thread th2");
                synchronized (s1) { //As another has runned parallely Line #11, lock has been created for s1
                    System.out.println(s1 + s2);
                }

            }
            System.out.println("Thread th2 has executed");
        }
    };

    public static void main(String[] args) {
        DeadlockApp deadLock = new DeadlockApp();
        deadLock.th1.start();
        deadLock.th2.start();
        //Line #51 and #52 runs parallely on executing the program, a lock is created inside synchronized method
        //A lock is nothing but, something like a blocker or wall, which holds access of the variable from being used by others.
        //Locked object is accessible, only when it is unlocked (i.e exiting  the synchronized block)
        //Lock cannot be created for primitive types (ex: int, float, double)
        //Dont forget to add thread.sleep(time) because if not added, then object access will not be at same time for both threads to create Deadlock (not actual runtime with lots of threads) 
        //This is a simple program, so we added sleep90 to create Deadlock, it will execute successfully, if it is removed. 
    }

    //Happy coding -- Parthasarathy S
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.