ตัวอย่างชวา - หยุดชะงักและแนวทางแก้ไข
การหยุดชะงักเป็นสถานการณ์ A: a ใหญ่ของหัวข้อที่ถูกบล็อกหนึ่งหรือทั้งหมดของพวกเขากำลังรอสำหรับทรัพยากรที่จะได้รับการปล่อยตัว ตั้งแต่ด้ายถูกบล็อกไปเรื่อย ๆ เพื่อให้โปรแกรมไม่สามารถยกเลิกได้ตามปกติ
สี่เงื่อนไขที่จำเป็น Java Deadlock:
- 1, การใช้งานพิเศษ, ที่อยู่, เมื่อทรัพยากรเป็นด้าย (ครอบครอง) หัวข้ออื่น ๆ ไม่สามารถใช้
- 2 ไม่สามารถยึดร้องขอทรัพยากรที่ไม่สามารถบังคับให้ยึดทรัพยากรจากมือของครอบครองทรัพยากรทรัพยากรทรัพยากรเท่านั้นที่สามารถออกโดยอาศัยความคิดริเริ่ม
- 3 คำขอและยืนยันว่าเมื่อผู้ร้องขอทรัพยากรในขณะที่ขอข้อมูลเพิ่มเติมเพื่อรักษาความครอบครองของทรัพยากรเดิม
- 4 รอวงจรกล่าวคือมีคิว: P1 P2 ครองทรัพยากร P2 P3 และทรัพยากรครอบครองที่ P1 หุ้น P3 ของทรัพยากร จึงสร้างห่วงรอ
เมื่อสี่เหล่านี้เงื่อนไขเป็นจริงแล้วการหยุดชะงัก แน่นอนถ้ากรณีของการหยุดชะงักในการทำลายเงื่อนไขใด ๆ เหล่านี้คุณสามารถปล่อยให้การหยุดชะงักหายไป ใช้รหัสต่อไปนี้เพื่อจำลองสิ่ง java หยุดชะงักการผลิต
วิธีการแก้ปัญหาการหยุดชะงักเป็นหนึ่งคือตรงกันหนึ่งคือการใช้ที่ชัดเจนสำหรับล็อคล็อค
หากใช้ไม่ถูกต้องของล็อคและหน้าจอในเวลาเดียวกันเมื่อคุณต้องการล็อควัตถุหลายที่จะมีสถานการณ์การหยุดชะงักดังต่อไปนี้:
/* author by w3cschool.cc LockTest.java */ import java.util.Date; public class LockTest { public static String obj1 = "obj1"; public static String obj2 = "obj2"; public static void main(String[] args) { LockA la = new LockA(); new Thread(la).start(); LockB lb = new LockB(); new Thread(lb).start(); } } class LockA implements Runnable{ public void run() { try { System.out.println(new Date().toString() + " LockA 开始执行"); while(true){ synchronized (LockTest.obj1) { System.out.println(new Date().toString() + " LockA 锁住 obj1"); Thread.sleep(3000); // 此处等待是给B能锁住机会 synchronized (LockTest.obj2) { System.out.println(new Date().toString() + " LockA 锁住 obj2"); Thread.sleep(60 * 1000); // 为测试,占用了就不放 } } } } catch (Exception e) { e.printStackTrace(); } } } class LockB implements Runnable{ public void run() { try { System.out.println(new Date().toString() + " LockB 开始执行"); while(true){ synchronized (LockTest.obj2) { System.out.println(new Date().toString() + " LockB 锁住 obj2"); Thread.sleep(3000); // 此处等待是给A能锁住机会 synchronized (LockTest.obj1) { System.out.println(new Date().toString() + " LockB 锁住 obj1"); Thread.sleep(60 * 1000); // 为测试,占用了就不放 } } } } catch (Exception e) { e.printStackTrace(); } } }
รหัสดังกล่าวจะดำเนินการส่งออกเป็น:
Tue May 05 10:51:06 CST 2015 LockB 开始执行 Tue May 05 10:51:06 CST 2015 LockA 开始执行 Tue May 05 10:51:06 CST 2015 LockB 锁住 obj2 Tue May 05 10:51:06 CST 2015 LockA 锁住 obj1
ที่หยุดชะงักนี้
เพื่อแก้ปัญหานี้เราไม่ได้ใช้เพื่อแสดงล็อคเราจะใช้ในการควบคุมการส่งสัญญาณ
สัญญาณสามารถควบคุมวิธีการหลายกระทู้สามารถเข้าถึงทรัพยากรที่เราระบุในที่นี้จะไม่สามารถเข้าถึงด้ายหนึ่งคุณทำล็อคที่คล้ายกัน สัญญาณสามารถระบุหมดเวลาที่จะได้รับเราสามารถตามไปหมดเวลาทำการรักษาเสริม
ในกรณีที่ไม่สามารถรับโดยทั่วไปคือการทำซ้ำความพยายามหรือระบุจำนวนของความพยายามที่คุณสามารถออกทันที
ดูรหัสต่อไปนี้:
/* author by w3cschool.cc UnLockTest.java */ import java.util.Date; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; public class UnLockTest { public static String obj1 = "obj1"; public static final Semaphore a1 = new Semaphore(1); public static String obj2 = "obj2"; public static final Semaphore a2 = new Semaphore(1); public static void main(String[] args) { LockAa la = new LockAa(); new Thread(la).start(); LockBb lb = new LockBb(); new Thread(lb).start(); } } class LockAa implements Runnable { public void run() { try { System.out.println(new Date().toString() + " LockA 开始执行"); while (true) { if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) { System.out.println(new Date().toString() + " LockA 锁住 obj1"); if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) { System.out.println(new Date().toString() + " LockA 锁住 obj2"); Thread.sleep(60 * 1000); // do something }else{ System.out.println(new Date().toString() + "LockA 锁 obj2 失败"); } }else{ System.out.println(new Date().toString() + "LockA 锁 obj1 失败"); } UnLockTest.a1.release(); // 释放 UnLockTest.a2.release(); Thread.sleep(1000); // 马上进行尝试,现实情况下do something是不确定的 } } catch (Exception e) { e.printStackTrace(); } } } class LockBb implements Runnable { public void run() { try { System.out.println(new Date().toString() + " LockB 开始执行"); while (true) { if (UnLockTest.a2.tryAcquire(1, TimeUnit.SECONDS)) { System.out.println(new Date().toString() + " LockB 锁住 obj2"); if (UnLockTest.a1.tryAcquire(1, TimeUnit.SECONDS)) { System.out.println(new Date().toString() + " LockB 锁住 obj1"); Thread.sleep(60 * 1000); // do something }else{ System.out.println(new Date().toString() + "LockB 锁 obj1 失败"); } }else{ System.out.println(new Date().toString() + "LockB 锁 obj2 失败"); } UnLockTest.a1.release(); // 释放 UnLockTest.a2.release(); Thread.sleep(10 * 1000); // 这里只是为了演示,所以tryAcquire只用1秒,而且B要给A让出能执行的时间,否则两个永远是死锁 } } catch (Exception e) { e.printStackTrace(); } } }
ตัวอย่างของโครงสร้างการส่งออกรหัสข้างต้น:
Tue May 05 10:59:13 CST 2015 LockA 开始执行 Tue May 05 10:59:13 CST 2015 LockB 开始执行 Tue May 05 10:59:13 CST 2015 LockB 锁住 obj2 Tue May 05 10:59:13 CST 2015 LockA 锁住 obj1 Tue May 05 10:59:14 CST 2015LockB 锁 obj1 失败 Tue May 05 10:59:14 CST 2015LockA 锁 obj2 失败 Tue May 05 10:59:15 CST 2015 LockA 锁住 obj1 Tue May 05 10:59:15 CST 2015 LockA 锁住 obj2