การทำงานพร้อมกันแบบมัลติเธรดสามารถทำได้ใน JAVA ผ่านทางคำสั่งซิงโครไนซ์ การใช้บล็อคโค้ดที่ซิงโครไนซ์ JVM ตรวจสอบให้แน่ใจว่ามีเพียงเธรดเดียวเท่านั้นที่สามารถล็อคบนอ็อบเจ็กต์บางอย่างได้ในเวลาเดียวกัน กลไกการล็อคช่วยให้หลายเธรดสามารถเข้าถึงทรัพยากรที่สำคัญได้อย่างปลอดภัย
รหัสการซิงโครไนซ์เขียนดังนี้:
รหัส 1:
Object obj = new Object(); ... ซิงโครไนซ์ (obj) { //TODO: เข้าถึงทรัพยากรที่สำคัญ} มัลติเธรดของ JAVA เต็มไปด้วยกับดักเสมอ หากเราใช้บูลีนเป็นออบเจ็กต์ที่ซิงโครไนซ์ อาจเกิดสถานการณ์สองสถานการณ์ต่อไปนี้:
1. เชื่อว่ามีวัตถุหนึ่งถูกล็อค แต่วัตถุที่แตกต่างกันนั้นซิงโครไนซ์กันจริงๆ
รหัส 2:
บูลีนระเหยส่วนตัว isTrue = false; publich void aMethod() { ... synchronized(isTrue) { isTrue = !isTrue; //TODO: เข้าถึงทรัพยากรที่สำคัญ isTrue = !isTrue; เมื่อดูเผินๆ โค้ดด้านบนก็ไม่มีอะไรผิดปกติ เนื่องจากมีการใช้การซิงโครไนซ์ (isTrue) จึงมีเธรดเดียวเท่านั้นที่สามารถเข้าถึงทรัพยากรที่สำคัญได้ในเวลาเดียวกัน แต่กรณีนี้ไม่เป็นเช่นนั้น เนื่องจากค่าคงที่ทั้งสองค่าเท็จและค่าจริงสอดคล้องกับวัตถุสองชิ้นที่แตกต่างกัน เมื่อมีการเปลี่ยนแปลง isTrue มีแนวโน้มว่าเธรดที่แตกต่างกันจะซิงโครไนซ์อ็อบเจ็กต์ที่แตกต่างกัน การชกมวยอัตโนมัติของ JAVA จะเปลี่ยน false เป็น Boolean.FALSE และ true เป็น Boolean.TRUE (ซึ่งยังแสดงให้เห็นว่าหาก false ถูกเปลี่ยนเป็น Boolean.FALSE ผลลัพธ์จะเหมือนเดิม) เขียนโค้ดทดสอบสำหรับสถานการณ์ข้อใดข้อหนึ่งข้างต้นดังต่อไปนี้:
รหัส 3:
BooleanTest ระดับสาธารณะ { บูลีนระเหยส่วนตัว isTrue = Boolean.FALSE; // มันจะเหมือนกันถ้าคุณใช้ false ที่นี่ public void aMethod() { for(int i=0;i<10;i++) { Thread t = new Thread() { public void run() { ซิงโครไนซ์ (isTrue) { isTrue = !isTrue; System.out.println(Thread.currentThread().getName() + " - isTrue=" + isTrue); ลอง{ วิ่งสองครั้ง = 1,000 * Math.random(); Thread.sleep(ran.intValue()); }catch(InterruptedException e) {} if(!isTrue) System.out.println( Thread.currentThread().getName() + " - โอ้ ไม่!"); isTrue = !isTrue; t.start(); } } โมฆะสาธารณะหลัก (String... args) { BooleanTest bt = new BooleanTest(); bt.aMethod(); เมื่อคุณรันโค้ดด้านบน คุณจะเห็น "-โอ้ ไม่!" เป็นครั้งคราว ซึ่งบ่งชี้ว่าเธรดต่างๆ เข้าสู่บล็อกโค้ดที่ซิงโครไนซ์พร้อมกัน
2. เชื่อกันว่าวัตถุต่างๆ ประสานกัน แต่จริงๆ แล้วเป็นวัตถุชิ้นเดียว
บางครั้งเราอาจต้องการซิงโครไนซ์กับออบเจ็กต์หลายรายการ หากใช้บูลีนเป็นออบเจ็กต์ที่ซิงโครไนซ์ อาจเป็นไปได้ว่าบล็อกการซิงโครไนซ์สองบล็อกที่ไม่ควรมีความสัมพันธ์จะใช้การล็อกออบเจ็กต์เดียวกัน ตัวอย่างมีดังนี้:
รหัส 4:
บูลีนระเหยง่าย aBoolean = Boolean.FALSE; บูลีนระเหยส่วนตัว anotherBoolean = false; โมฆะสาธารณะ aMethod () { ... ซิงโครไนซ์ (aBoolean) { // TODO: เข้าถึงทรัพยากรที่สำคัญ 1 } ... } โมฆะสาธารณะ anotherMethod () { .. ซิงโครไนซ์ (anotherBoolean) { //TODO: เข้าถึงทรัพยากรที่สำคัญ 2 } ... } สมมติว่าแต่เดิม aMethod และ anotherMethod จะถูกเรียกโดยเธรดที่ไม่เกี่ยวข้องสองชุด อย่างไรก็ตาม เนื่องจาก Boolean.FALSE และ false ชี้ไปที่วัตถุเดียวกัน การเข้าถึงทรัพยากรที่สำคัญ 2 อาจถูกบล็อกโดยทรัพยากรที่สำคัญ 1 (และในทางกลับกัน)
สองสถานการณ์ข้างต้นบ่งชี้ว่าเมื่อใช้บล็อกที่ซิงโครไนซ์ พยายามอย่าใช้วัตถุบูลีนเป็นวัตถุที่ซิงโครไนซ์ ไม่เช่นนั้นอาจเกิดปัญหาที่ไม่คาดคิด หรือกับดักอาจเกิดจากการแก้ไขโค้ดในอนาคต
นอกจากนี้ยังสามารถเห็นได้จากสิ่งนี้ว่าการซิงโครไนซ์ค่าคงที่ใด ๆ มีความเสี่ยง หากคุณต้องซิงโครไนซ์บูลีน คุณต้องใช้ตัวดำเนินการใหม่เพื่อสร้างออบเจ็กต์บูลีน