0. เกี่ยวกับการซิงโครไนซ์เธรด (1) ทำไมเราต้องซิงโครไนซ์มัลติเธรด?
การซิงโครไนซ์เธรดหมายถึงการอนุญาตให้มีเธรดที่รันหลายตัวให้ความร่วมมือร่วมกันเพื่อให้หลายเธรดสามารถครอบครองและปล่อยทรัพยากรตามที่ต้องการได้อย่างสมเหตุสมผล เราใช้บล็อกรหัสการซิงโครไนซ์และวิธีการซิงโครไนซ์ใน Java เพื่อให้บรรลุเป้าหมายนี้ ตัวอย่างเช่นแก้ปัญหาการดำเนินการสั่งซื้อแบบมัลติเธรดที่ไม่ได้ดำเนินการ:
คลาสสาธารณะ twoThreadTest {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {เธรด Th1 = ใหม่ mythread1 (); เธรด th2 = ใหม่ mythread2 (); Th1.start (); Th2.start (); }} คลาส mythread2 ขยายเธรด {@Override โมฆะสาธารณะเรียกใช้ () {สำหรับ (int i = 0; i <10; i ++) ระบบ out.println ("เธรด 1 ตัวนับ:"+i); }} คลาส mythread1 ขยายเธรด {@override โมฆะสาธารณะเรียกใช้ () {สำหรับ (int i = 0; i <10; i ++) ระบบ out.println ("เธรด 1 ตัวนับ:"+i); }} คลาส mythread1 ขยายเธรด {@override โมฆะสาธารณะเรียกใช้ () {สำหรับ (int i = 0; i <10; i ++) ระบบ out.println ("เธรด 2 ตัวนับ:"+i); -ผลลัพธ์ของการดำเนินการแบบมัลติเธรดในสถานะนี้คือการแทรกการดำเนินการแบบสุ่มตามความประสงค์ซึ่งขึ้นอยู่กับการกำหนดเวลาเธรดของ JVM ทั้งหมด ในหลายกรณีที่จำเป็นต้องมีการดำเนินการอย่างเป็นระเบียบสถานะการดำเนินการแบบสุ่มนี้ไม่เหมาะสมอย่างเห็นได้ชัด
ชั้นเรียนสาธารณะ ThreadTest {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {เธรด MyThread = new MyThread (); เธรด Th1 = เธรดใหม่ (เธรด); เธรด Th2 = เธรดใหม่ (เธรด); Th1.start (); Th2.start (); }} คลาส MyThread ดำเนินการ runnable {@Override public synchronized void run () {สำหรับ (int i = 0; i <10; i ++) ระบบ out.println (เธรด. currentthread (). getName ()+"ตัวนับ:"+i); -หลังจากใช้วิธีการซิงโครไนซ์เราสามารถควบคุมเธรดเพื่อครอบครองวัตถุร่างกายการดำเนินการโดยเฉพาะ ด้วยวิธีนี้ในระหว่างกระบวนการดำเนินการเธรดสามารถดำเนินการงานในหน่วยงานการดำเนินการในครั้งเดียวและออกจากสถานะล็อค จากนั้น JVM จะส่งเธรดอื่นเพื่อเรียกใช้งานในร่างกายการดำเนินการในครั้งเดียว
(2) กระบวนทัศน์สำหรับการสร้างเธรดและการทำงาน:
ในอดีตเรายังมีกระบวนทัศน์การเขียนโปรแกรมของเราเองสำหรับการสร้างด้ายและการทำงาน โดยทั่วไปเราได้กำหนดคลาสการดำเนินการเพื่อเขียนวิธีการเรียกใช้ () แต่วิธีนี้ทำให้หน่วยงานดำเนินการและงานที่ดำเนินการเข้าด้วยกันซึ่งไม่เอื้อต่อการแยกออกจากมุมมองของวิศวกรรมซอฟต์แวร์ การดำเนินการของเธรดหมายความว่าเธรดดำเนินการงานของวัตถุผ่านวัตถุการดำเนินการ จากมุมมองนี้การแยกผู้สั่งงานของงานออกจากคลาสการดำเนินการสามารถทำให้บทบาทต่าง ๆ ของการเขียนโปรแกรมแบบมัลติเธรดที่ชัดเจนและทำให้ได้รับ decoupling ที่ดี ต่อไปนี้เป็นกระบวนทัศน์การเขียนโปรแกรมสำหรับการสร้างเธรดและการดำเนินการ:
คลาสสาธารณะ FormalThreadClass {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {เธรดเธรด = เธรดใหม่ (ใหม่ myrunnable ()); thread.start (); }} คลาส myrunnable onplunable runnable {mytask mytask = new mytask (); @Override โมฆะสาธารณะ Run () {myTask.dotask (); }} คลาส mytask {โมฆะสาธารณะ Dotask () {ระบบ out.println ("นี่คืองานจริง"); -
1. หลักการที่ซิงโครไนซ์
ใน Java แต่ละวัตถุมีและมีเพียงหนึ่งล็อคการซิงโครไนซ์ นอกจากนี้ยังหมายความว่าการล็อคการซิงโครไนซ์มีอยู่ในวัตถุ
เมื่อเราเรียกวิธีการซิงโครไนซ์ของวัตถุเราจะได้รับการล็อคการซิงโครไนซ์ของวัตถุ ตัวอย่างเช่นซิงโครไนซ์ (OBJ) ได้รับการล็อคการซิงโครไนซ์ของ "OBJ Object"
การเข้าถึงล็อคการซิงโครไนซ์โดยเธรดที่แตกต่างกันนั้นไม่เกิดร่วมกัน กล่าวอีกนัยหนึ่ง ณ เวลาหนึ่งเวลาล็อคการซิงโครไนซ์ของวัตถุสามารถรับได้โดยหนึ่งเธรด! ผ่านการล็อคการซิงโครไนซ์เราสามารถเข้าถึงการเข้าถึง "วัตถุ/วิธีการ" ซึ่งกันและกันร่วมกันในหลายเธรด ตัวอย่างเช่นขณะนี้มีสองเธรด A และ Thread B ซึ่งทั้งสองเข้าถึง "การล็อคแบบซิงโครนัสของ Object OBJ" สมมติว่าในบางจุดเธรด A ได้มา "ล็อคการซิงโครไนซ์ของ OBJ" และดำเนินการบางอย่าง ในเวลานี้เธรด B ยังพยายามที่จะได้รับ "การเชื่อมโยงการซิงโครไนซ์ของ OBJ" - เธรด B จะล้มเหลวในการรับมันจะต้องรอจนกว่าเธรดจะปล่อย "ล็อคการซิงโครไนซ์ของ OBJ" และสามารถเรียกใช้ได้เท่านั้น
2. กฎพื้นฐานที่ซิงโครไนซ์
เราสรุปกฎพื้นฐานของการซิงโครไนซ์ลงใน 3 ต่อไปนี้และแสดงให้เห็นผ่านตัวอย่าง
บทความที่ 1: เมื่อเธรดเข้าถึง "วิธีการซิงโครไนซ์" หรือ "บล็อกรหัสที่ซิงโครไนซ์" ของ "วัตถุบางอย่าง" เธรดอื่นจะถูกบล็อกจากการเข้าถึง "วิธีการซิงโครไนซ์" หรือ "บล็อกรหัสที่ซิงโครไนซ์" ของ "วัตถุ"
บทความที่ 2: เมื่อเธรดเข้าถึง "วิธีการซิงโครไนซ์" หรือ "บล็อกรหัสที่ซิงโครไนซ์" ของ "วัตถุบางอย่าง" เธรดอื่น ๆ ยังสามารถเข้าถึงบล็อกรหัสแบบอะซิงโครไนซ์ของ "วัตถุนี้"
ข้อ 3: เมื่อเธรดเข้าถึง "วิธีการซิงโครไนซ์" หรือ "บล็อกรหัสที่ซิงโครไนซ์" ของ "วัตถุบางอย่าง" เธรดอื่นจะถูกบล็อกจากการเข้าถึง "วิธีการซิงโครไนซ์" อื่น ๆ หรือ "บล็อกรหัสที่ซิงโครไนซ์" ของ "วัตถุ"
(1) บทความ 1:
เมื่อเธรดเข้าถึง "วิธีการซิงโครไนซ์" หรือ "บล็อกรหัสที่ซิงโครไนซ์" ของ "วัตถุบางอย่าง" เธรดอื่นจะถูกบล็อกจากการเข้าถึงไปยัง "วิธีการซิงโครไนซ์" หรือ "บล็อกรหัสที่ซิงโครไนซ์" ของ "วัตถุ" ด้านล่างนี้เป็นโปรแกรมสาธิตที่สอดคล้องกับ "บล็อกรหัสที่ซิงโครไนซ์"
คลาส myrunable onplunable runnable {@override public void run () {ซิงโครไนซ์ (นี่) {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName () + "loop" + i); }} catch (interruptedException IE) {}}}} คลาสสาธารณะ DEMO1_1 {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {runnable demo = new myrunable (); // สร้างเธรด "Runnable Object" ใหม่ t1 = เธรดใหม่ (ตัวอย่าง, "T1"); // สร้าง "เธรด T1" ใหม่ T1 ขึ้นอยู่กับเธรดวัตถุที่เรียกใช้งาน T2 = เธรดใหม่ (ตัวอย่าง, "T2"); // สร้าง "เธรด T2" ใหม่ T2 ขึ้นอยู่กับวัตถุที่เรียกใช้ t1.start (); // เริ่มต้น "เธรด t1" t2.start (); // เริ่ม "เธรด t2"}} ผลการทำงาน:
T1 LOOP 0T1 LOOP 1T1 LOOP 2T1 LOOP 3T1 LOOP 4T2 LOOP 0T2 LOOP 1T2 LOOP 2T2 LOOP 3T2 LOOP 4
ผลการวิจัยแสดงให้เห็นว่ามี "บล็อกรหัสที่ซิงโครไนซ์ (นี้) ในวิธีการเรียกใช้ () และ T1 และ T2 เป็นเธรดที่สร้างขึ้นตามวัตถุ" สาธิต " ซึ่งหมายความว่าเราสามารถพิจารณาสิ่งนี้ในการซิงโครไนซ์ (นี่) เป็น "วัตถุที่เรียกใช้งานได้"; ดังนั้นเธรด T1 และ T2 แบ่งปัน "การล็อคแบบซิงโครนัสของวัตถุสาธิต" ดังนั้นเมื่อเธรดหนึ่งกำลังทำงานอยู่เธรดอื่นจะต้องรอ "เธรดที่รัน" เพื่อปล่อย "ล็อคการซิงโครไนซ์การสาธิต" ก่อนที่จะทำงาน
หากคุณยืนยันคุณจะพบปัญหานี้ จากนั้นเราแก้ไขรหัสด้านบนแล้วเรียกใช้เพื่อดูว่าผลลัพธ์เป็นอย่างไรและดูว่าคุณจะสับสนหรือไม่ ซอร์สโค้ดที่แก้ไขมีดังนี้:
คลาส MyThread ขยายเธรด {Public MyThread (ชื่อสตริง) {super (ชื่อ); } @Override โมฆะสาธารณะเรียกใช้ () {ซิงโครไนซ์ (นี่) {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName () + "loop" + i); }} catch (interruptedException IE) {}}}} คลาสสาธารณะ Demo1_2 {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {เธรด t1 = ใหม่ mythread ("t1"); // สร้าง "เธรด t1" ใหม่เธรด t2 = new mythread ("t2"); // สร้าง "เธรด t2" ใหม่ t1.start (); // เริ่มต้น "เธรด t1" t2.start (); // เริ่ม "เธรด t2"}} คำอธิบายรหัส: การเปรียบเทียบ DEMO1_2 และ DEMO1_1 เราพบว่าคลาส MyThread ใน DEMO1_2 ได้รับการสืบทอดโดยตรงจากเธรดและ T1 และ T2 เป็นทั้งเธรดเด็ก MyThread
โชคดีที่วิธี "Run () ของ DEMO1_2" เรียกอีกอย่างว่าซิงโครไนซ์ (นี่) เช่นเดียวกับวิธี "Run () ของ Demo1_1" หรือที่เรียกว่าซิงโครไนซ์ (นี่)!
ดังนั้นกระบวนการดำเนินการของ DEMO1_2 เหมือนกับ DEMO1_1 หรือไม่? ผลการทำงาน:
T1 LOOP 0T2 LOOP 0T1 LOOP 1T2 LOOP 1T1 LOOP 2T2 LOOP 2T1 LOOP 3T2 LOOP 3T1 LOOP 4T2 LOOP 4
ผลลัพธ์คำอธิบาย:
หากผลลัพธ์นี้ไม่ทำให้คุณประหลาดใจเลยฉันเชื่อว่าคุณมีความเข้าใจที่ลึกซึ้งยิ่งขึ้นเกี่ยวกับการซิงโครไนซ์และสิ่งนี้ มิฉะนั้นโปรดอ่านการวิเคราะห์ต่อไปที่นี่
สิ่งนี้อยู่ในการซิงโครไนซ์ (นี่) หมายถึง "วัตถุคลาสปัจจุบัน" นั่นคือวัตถุปัจจุบันที่สอดคล้องกับคลาสที่อยู่ในตำแหน่งที่ซิงโครไนซ์ (นี้) อยู่ วัตถุประสงค์คือเพื่อให้ได้ "ล็อคแบบซิงโครนัสของวัตถุปัจจุบัน"
สำหรับ DEMO1_2 สิ่งนี้อยู่ในการซิงโครไนซ์ (นี่) หมายถึงวัตถุในตำนานในขณะที่ T1 และ T2 เป็นวัตถุที่แตกต่างกันสองวัตถุ ดังนั้นเมื่อ T1 และ T2 ดำเนินการซิงโครไนซ์ (นี่) พวกเขาจะได้รับการเชื่อมโยงการซิงโครไนซ์ของวัตถุที่แตกต่างกัน สำหรับคู่ Demo1_1 สิ่งนี้อยู่ในการซิงโครไนซ์ (นี้) แสดงถึงวัตถุ myrunable; T1 และ T2 แบ่งปันวัตถุที่ไม่สามารถเข้าถึงได้ ดังนั้นเธรดหนึ่งจึงได้รับการล็อคการซิงโครไนซ์ของวัตถุซึ่งจะทำให้เธรดอื่นรอ
(2) บทความ 2:
เมื่อเธรดเข้าถึง "วิธีการซิงโครไนซ์" หรือ "บล็อกรหัสที่ซิงโครไนซ์" ของ "วัตถุบางอย่าง" เธรดอื่น ๆ ยังสามารถเข้าถึงบล็อกรหัสแบบอะซิงโครไนซ์ของ "วัตถุนี้"
ด้านล่างนี้เป็นโปรแกรมสาธิตที่สอดคล้องกับ "บล็อกรหัสที่ซิงโครไนซ์"
การนับคลาส {// วิธีการที่มีการซิงโครไนซ์ซิงโครไนซ์บล็อกโมฆะสาธารณะ synmethod () {ซิงโครไนซ์ (นี่) {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep สำหรับ 100ms system.out.println (thread.currentthread (). getName () + "synmethod loop" + i); }} catch (interruptedException ie) {}}} // วิธีการแบบอะซิงโครนัสโมฆะสาธารณะ nonsynmethod () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); System.out.println (thread.currentthread (). getName () + "nonsynmethod loop" + i); }} catch (interruptedException ie) {}}} คลาสสาธารณะ Demo2 {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {นับจำนวนสุดท้าย = นับใหม่ (); // สร้าง T1 ใหม่ T1 จะเรียกวิธีการ synmethod () ของ "count object" เธรด t1 = เธรดใหม่ (ใหม่ runnable () {@Override โมฆะสาธารณะเรียกใช้ () {count.synmethod ();}}, "t1"); // สร้าง T2 ใหม่ T2 จะเรียกวิธีการ nonsynmethod () ของ "count object" เธรด t2 = เธรดใหม่ (ใหม่ runnable () {@Override public void run () {count.nonsynmethod ();}}, "t2"); t1.start (); // เริ่ม t1 t2.start (); // เริ่ม t2}} ผลการทำงาน:
T1 synmethod loop 0t2 nonsynmethod loop 0t1 synmethod loop 1t2 nonsynmethod loop 1t1 synmethod loop 2t2 nonsynmethod loop 2T1 synmethod loop 3T2 nonsynmethod loop 3T1 synmethod 4T2 Nonsynmethod
ผลลัพธ์คำอธิบาย:
สองเธรดเด็กใหม่ T1 และ T2 ถูกสร้างขึ้นในเธรดหลัก T1 จะเรียกวิธีการ synmethod () ของวัตถุนับซึ่งมีบล็อกการซิงโครไนซ์; T2 จะเรียกวิธี Nonsynmethod () ของวัตถุนับซึ่งไม่ใช่วิธีการซิงโครไนซ์ เมื่อ T1 กำลังทำงานแม้ว่าจะถูกเรียกว่าซิงโครไนซ์ (นี้) เพื่อให้ได้ "ล็อคการซิงโครไนซ์นับ"; มันไม่ได้ทำให้ T2 บล็อกเนื่องจาก T2 ไม่ได้ใช้การล็อคการซิงโครไนซ์ "นับ"
(3) บทความ 3:
เมื่อเธรดเข้าถึง "วิธีการซิงโครไนซ์" หรือ "บล็อกรหัสที่ซิงโครไนซ์" ของ "วัตถุบางอย่าง" เธรดอื่น ๆ จะเข้าถึง "วิธีการซิงโครไนซ์" อื่น ๆ หรือ "บล็อกรหัสที่ซิงโครไนซ์" ของ "วัตถุ" จะถูกบล็อก
นอกจากนี้เรายังจะปรับเปลี่ยนวิธีการที่ไม่ซิงซิง () ในตัวอย่างข้างต้นด้วยการซิงโครไนซ์ (นี้) ซอร์สโค้ดที่แก้ไขมีดังนี้:
การนับคลาส {// วิธีการที่มีการซิงโครไนซ์ซิงโครไนซ์บล็อกโมฆะสาธารณะ synmethod () {ซิงโครไนซ์ (นี่) {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep สำหรับ 100ms system.out.println (thread.currentthread (). getName () + "synmethod loop" + i); }} catch (interruptedException IE) {}}} // วิธีที่มีการซิงโครไนซ์ซิงโครไนซ์บล็อกโมฆะสาธารณะ nonsynmethod () {ซิงโครไนซ์ (นี่) {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); System.out.println (thread.currentthread (). getName () + "nonsynmethod loop" + i); }} catch (interruptedException IE) {}}}} คลาสสาธารณะ Demo3 {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {นับจำนวนสุดท้าย = นับใหม่ (); // สร้าง t1, t1 จะเรียกวิธี synmethod () ของ "count object" เธรด t1 = เธรดใหม่ (ใหม่ runnable () {@Override public void run () {count.syncMethod ();}}, "t1"); // สร้าง T2 ใหม่ T2 จะเรียกวิธีการ nonsynmethod () ของ "count object" เธรด t2 = เธรดใหม่ (ใหม่ runnable () {@Override โมฆะสาธารณะเรียกใช้ () {count.nonsynmethod ();}}, "t2"); t1.start (); // เริ่ม t1 t2.start (); // เริ่ม t2}} ผลการทำงาน:
T1 synmethod loop 0T1 synmethod loop 1t1 synmethod loop 2T1 synmethod loop 3T1 synmethod loop 4T2 nonsynmethod loop 0T2 nonsynmethod loop 1t2 nonsynmethod loop 2T2 Nonsynmethod 3T2 Nonsynmethod
ผลลัพธ์คำอธิบาย:
สองเธรดเด็กใหม่ T1 และ T2 ถูกสร้างขึ้นในเธรดหลัก ทั้งการเรียกใช้ T1 และ T2 Synchronized (นี่) ซึ่งเป็นจำนวนวัตถุนับ (นับ) และจำนวนหุ้น T1 และ T2 ดังนั้นเมื่อ T1 กำลังทำงาน T2 จะถูกบล็อกและ T1 จะเรียกใช้เพื่อปล่อย "การล็อคแบบซิงโครนัสของวัตถุนับ" ก่อนที่ T2 จะทำงานได้
3. วิธีการซิงโครไนซ์และบล็อกรหัสที่ซิงโครไนซ์
"วิธีการซิงโครไนซ์" ใช้วิธีการปรับเปลี่ยนแบบซิงโครไนซ์ในขณะที่ "บล็อกรหัสที่ซิงโครไนซ์" ใช้บล็อกรหัสการปรับเปลี่ยนซิงโครไนซ์
ตัวอย่างวิธีการซิงโครไนซ์
Void FOO1 () {System.out.println ("วิธีการซิงโครไนซ์");} รหัสที่ซิงโครไนซ์บล็อกโมฆะสาธารณะ foo2 () {ซิงโครไนซ์ (นี้) {system.out.println ("วิธีการซิงโครไนซ์"); - สิ่งนี้ในบล็อกรหัสที่ซิงโครไนซ์หมายถึงวัตถุปัจจุบัน นอกจากนี้ยังสามารถแทนที่ด้วยวัตถุอื่น ๆ เช่นนี้ถูกแทนที่ด้วย OBJ จากนั้น foo2 () จะได้รับการล็อคการซิงโครไนซ์ของ OBJ เมื่อซิงโครไนซ์ (OBJ)
บล็อกรหัสที่ซิงโครไนซ์สามารถควบคุมพื้นที่การเข้าถึงที่จำกัดความขัดแย้งได้อย่างแม่นยำมากขึ้นและบางครั้งก็มีประสิทธิภาพมากขึ้น นี่คือตัวอย่างที่จะแสดง:
// demo4.java ซอร์สโค้ดระดับสาธารณะ Demo4 {โมฆะที่ซิงโครไนซ์สาธารณะ synmethod () {สำหรับ (int i = 0; i <1000000; i ++); } โมฆะสาธารณะ synblock () {ซิงโครไนซ์ (นี่) {สำหรับ (int i = 0; i <10,0000000; i ++); }} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {demo4 demo = ใหม่ demo4 (); เริ่มต้นยาวแตกต่าง; start = system.currentTimeMillis (); // รับเวลาปัจจุบัน (มิลลิส) demo.syncmethod (); // โทร "วิธีการซิงโครไนซ์" diff = system.currentTimeMillis () - เริ่ม; // รับ "ความแตกต่างเวลา" System.out.println ("syncMethod ():"+ diff); start = system.currentTimeMillis (); // รับเวลาปัจจุบัน (มิลลิส) demo.syncblock (); // เรียกว่า "บล็อกวิธีการซิงโครไนซ์" diff = system.currentTimeMillis () - เริ่ม; // รับ "ความแตกต่างเวลา" System.out.println ("SyncBlock ():"+ diff); - (ครั้งเดียว) ผลการดำเนินการ:
Synmethod (): 11Synblock (): 3
4. ล็อคอินสแตนซ์และล็อคทั่วโลก
อินสแตนซ์ล็อค-ล็อคบนวัตถุอินสแตนซ์ หากชั้นเรียนเป็นซิงเกิลตันแล้วล็อคก็มีแนวคิดของการล็อคทั่วโลก
(1) คำหลักที่ซิงโครไนซ์สอดคล้องกับการล็อคอินสแตนซ์
(2) Global Lock-ล็อคถูกกำหนดเป้าหมายในชั้นเรียน ไม่ว่าอินสแตนซ์จะมีวัตถุกี่ชิ้นเธรดจะแชร์ล็อค
ล็อคทั่วโลกสอดคล้องกับการซิงโครไนซ์แบบคงที่ (หรือล็อคบนคลาสหรือวัตถุคลาสโหลดของคลาสนี้)
มีตัวอย่างที่ชัดเจนของ "ล็อคอินสแตนซ์" และ "ล็อคทั่วโลก":
Pulbic Class บางอย่าง {public synchronized void issynca () {} public synchronized void issyncb () {} public synchronized void csynca () {} โมฆะแบบคงที่แบบคงที่ cyncb () {}}}}}}}}}}}}} สมมติว่ามีบางอย่างมีสองอินสแตนซ์ x และ y วิเคราะห์ล็อคที่ได้รับโดยนิพจน์สี่ชุดต่อไปนี้
(1) X.ISSYNCA () และ X.ISSYNCB ()
(2) x.issynca () และ y.issynca ()
(3) x.csynca () และ y.csyncb ()
(4) x.issynca () และบางสิ่งบางอย่าง csynca ()
(1) ไม่สามารถเข้าถึงได้พร้อมกัน
เพราะ ISSYNCA () และ ISSYNCB () เป็นล็อคการซิงโครไนซ์ที่เข้าถึงวัตถุเดียวกัน (วัตถุ X)!
// locktest1.java คลาสซอร์สโค้ดคลาสบางสิ่งบางอย่าง {โมฆะที่ซิงโครไนซ์สาธารณะ issynca () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": issynca"); }} catch (interruptedException IE) {}} โมฆะที่ซิงโครไนซ์สาธารณะ issyncb () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep สำหรับ 100ms system.out.println (thread.currentthread (). getName ()+": issyncb"); }} catch (interruptedException ie) {}}} คลาสสาธารณะ LockTest1 {บางสิ่งบางอย่าง x = ใหม่บางสิ่งบางอย่าง (); บางสิ่งบางอย่าง y = สิ่งใหม่ (); // เปรียบเทียบ (01) x.issynca () กับ x.issyncb () โมฆะส่วนตัว test1 () {// สร้าง T11 ใหม่ T11 จะเรียก X.ISSYNCA () เธรด t11 = เธรดใหม่ // สร้าง T12 ใหม่ T12 จะเรียก X.ISSYNCB () เธรด t12 = เธรดใหม่ (ใหม่ runnable () {@Override โมฆะสาธารณะเรียกใช้ () {x.issyncb ();}}, "t12"); t11.start (); // เริ่ม t11 t12.start (); // เริ่ม t12} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {locktest1 demo = new LockTest1 (); demo.test1 (); - ผลการทำงาน:
T11: ISSYNCAT11: ISSYNCAT11: ISSYNCAT11: ISSYNCAT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBT12: ISSYNCBBB
(2) สามารถเข้าถึงได้ในเวลาเดียวกัน
เนื่องจากไม่ได้เข้าถึงการล็อคการซิงโครไนซ์ของวัตถุเดียวกัน x.issynca () เข้าถึงการล็อคการซิงโครไนซ์ของ x ในขณะที่ y.issynca () เข้าถึงล็อคการซิงโครไนซ์ของ y
// locktest2.java คลาสซอร์สโค้ดคลาสบางสิ่งบางอย่าง {โมฆะที่ซิงโครไนซ์สาธารณะ issynca () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": issynca"); }} catch (interruptedException IE) {}} โมฆะที่ซิงโครไนซ์สาธารณะ issyncb () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": issyncb"); }} catch (interruptedException IE) {}} โมฆะแบบสแตติกแบบคงที่สาธารณะ csynca () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": csynca"); }} catch (interruptedException IE) {}} โมฆะแบบสแตติกแบบคงที่สาธารณะ csyncb () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": csyncb"); }} catch (interruptedException ie) {}}} คลาสสาธารณะ LockTest2 {บางสิ่งบางอย่าง x = ใหม่บางสิ่งบางอย่าง (); บางสิ่งบางอย่าง y = สิ่งใหม่ (); // เปรียบเทียบ (02) x.issynca () กับ y.issynca () โมฆะส่วนตัว test2 () {// สร้าง T21 ใหม่ T21 จะเรียก X.ISSYNCA () เธรด T21 = เธรดใหม่ // สร้าง T22 ใหม่ T22 จะเรียก X.ISSYNCB () เธรด t22 = เธรดใหม่ (ใหม่ runnable () {@Override โมฆะสาธารณะเรียกใช้ () {y.issynca ();}}, "t22"); t21.start (); // เริ่ม t21 t22.start (); // เริ่ม t22} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {locktest2 demo = new LockTest2 (); demo.test2 (); - ผลการทำงาน:
T21: ISSYNCAT22: ISSYNCAT21: ISSYNCAT22: ISSYNCAT21: ISSYNCAT22: ISSYNCAT21: ISSYNCAT22: ISSYNCAT21: ISSYNCAT22: ISSYNCAT21: ISSYNCAT22: ISSYNCAT21: ISSYNCAT22222
(3) ไม่สามารถเข้าถึงได้พร้อมกัน
เนื่องจาก csynca () และ csyncb () เป็นทั้งประเภทคงที่ x.csynca () เทียบเท่ากับบางสิ่งบางอย่าง issynca () และ y.csyncb () เทียบเท่ากับบางสิ่งบางอย่าง issyncb ()
// locktest3.java คลาสซอร์สโค้ดคลาสบางสิ่งบางอย่าง {โมฆะที่ซิงโครไนซ์สาธารณะ issynca () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": issynca"); }} catch (interruptedException IE) {}} โมฆะที่ซิงโครไนซ์สาธารณะ issyncb () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": issyncb"); }} catch (interruptedException IE) {}} โมฆะแบบสแตติกแบบคงที่สาธารณะ csynca () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": csynca"); }} catch (interruptedException IE) {}} โมฆะแบบสแตติกแบบคงที่สาธารณะ csyncb () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": csyncb"); }} catch (interruptedException IE) {}}} คลาสสาธารณะ LockTest3 {บางสิ่งบางอย่าง x = ใหม่บางสิ่งบางอย่าง (); บางสิ่งบางอย่าง y = สิ่งใหม่ (); // เปรียบเทียบ (03) x.csynca () กับ y.csyncb () โมฆะส่วนตัว test3 () {// สร้าง T31 ใหม่, t31 จะเรียก X.ISSYNCA () เธรด t31 = เธรดใหม่ // สร้าง T32 ใหม่ T32 จะเรียก X.ISSYNCB () เธรด t32 = เธรดใหม่ (ใหม่ runnable () {@Override โมฆะสาธารณะเรียกใช้ () {y.csyncb ();}}, "t32"); t31.start (); // เริ่ม t31 t32.start (); // เริ่ม t32} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {locktest3 demo = new LockTest3 (); demo.test3 (); - ผลการทำงาน:
T31: CSYNCAT31: CSYNCAT31: CSYNCAT31: CSYNCAT31: CSYNCAT32: CSYNCBT32: CSYNCBT32: CSYNCBT32: CSYNCBT32: CSYNCBT32: CSYNCBT32: CSYNCBT32 csyncb
(4) สามารถเข้าถึงได้พร้อมกัน
เนื่องจาก issynca () เป็นวิธีการอินสแตนซ์, x.issynca () ใช้ล็อคของวัตถุ x; ในขณะที่ csynca () เป็นวิธีการคงที่บางอย่าง csynca () สามารถเข้าใจได้ว่ามันเป็น "ล็อคคลาส" ที่ใช้ ดังนั้นพวกเขาสามารถเข้าถึงได้พร้อมกัน
// locktest4.java คลาสซอร์สโค้ดคลาสบางสิ่งบางอย่าง {โมฆะที่ซิงโครไนซ์สาธารณะ issynca () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": issynca"); }} catch (interruptedException IE) {}} โมฆะที่ซิงโครไนซ์สาธารณะ issyncb () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": issyncb"); }} catch (interruptedException IE) {}} โมฆะแบบสแตติกแบบคงที่สาธารณะ csynca () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep 100ms system.out.println (thread.currentthread (). getName ()+": csynca"); }} catch (interruptedException IE) {}} โมฆะแบบสแตติกแบบคงที่สาธารณะ csyncb () {ลอง {สำหรับ (int i = 0; i <5; i ++) {thread.sleep (100); // sleep สำหรับ 100ms system.out.println (thread.currentthread (). getName ()+": csyncb"); }} catch (interruptedException ie) {}}} คลาสสาธารณะ LockTest4 {บางสิ่งบางอย่าง x = ใหม่บางสิ่งบางอย่าง (); บางสิ่งบางอย่าง y = สิ่งใหม่ (); // เปรียบเทียบ (04) x.issynca () กับบางสิ่งบางอย่าง csynca () โมฆะส่วนตัว test4 () {// สร้าง T41 ใหม่ t41 จะเรียก X.ISSYNCA () เธรด t41 = เธรดใหม่ // สร้าง T42 ใหม่, T42 จะเรียก X.ISSYNCB () เธรด t42 = เธรดใหม่ (ใหม่ runnable () {@Override โมฆะสาธารณะเรียกใช้ () {something.csynca ();}}, "t42"); t41.start (); // เริ่ม t41 t42.start (); // เริ่ม t42} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {locktest4 demo = new LockTest4 (); demo.test4 (); - ผลการทำงาน:
T41: ISSYNCAT42: CSYNCAT41: ISSYNCAT42: CSYNCAT41: ISSYNCAT42: CSYNCAT41: ISSYNCAT42: CSYNCAT41: ISSYNCAT42: CSYNCAT41: ISSYNCAT42: CSYNCAT41: ISSYNCAT41