1. สถานการณ์ที่ใช้งานได้สำหรับ CAS และซิงโครไนซ์
1. สำหรับสถานการณ์ที่การแข่งขันทรัพยากรน้อยลงโดยใช้การซิงโครไนซ์แบบซิงโครไนซ์ล็อคสำหรับการปิดกั้นเธรดและการสลับการปลุกและการสลับการทำงานระหว่างเมล็ดของผู้ใช้รัฐคือการเสียทรัพยากร CPU เป็นพิเศษ ในขณะที่ CAS ถูกนำไปใช้ตามฮาร์ดแวร์ไม่จำเป็นต้องป้อนเคอร์เนลไม่จำเป็นต้องสลับเธรดและโอกาสในการหมุนจะน้อยลงดังนั้นประสิทธิภาพที่สูงขึ้นสามารถรับได้
2. ในกรณีที่มีการแข่งขันทรัพยากรอย่างจริงจังความน่าจะเป็นของการหมุน CAS ค่อนข้างสูงดังนั้นการสูญเสียทรัพยากร CPU มากขึ้นและมีประสิทธิภาพน้อยกว่าการซิงโครไนซ์ การใช้คลาส Atomicinteger ในแพ็คเกจ java.util.concurrent.atomic เป็นตัวอย่างวิธีการ getandincrement () ของมันถูกนำมาใช้ดังนี้:
public int final int getandincrement () {สำหรับ (;;) {int current = get (); int next = current + 1; ถ้า (เปรียบเทียบ (ปัจจุบัน, ถัดไป)) ส่งคืนกระแส; -หากวิธีการเปรียบเทียบ (ปัจจุบัน, ถัดไป) ถูกดำเนินการสำเร็จจะถูกส่งคืนโดยตรง หากการแข่งขันเธรดนั้นรุนแรงขึ้นจะส่งผลให้วิธีการเปรียบเทียบ (ปัจจุบัน, ถัดไป) ที่ไม่สามารถดำเนินการได้สำเร็จมันจะถูกวนและรอจนกว่าจะถึงเวลาที่จัดสรร CPU ไปยังเธรดจะหมดลงอย่างมาก
2. CAS ข้อผิดพลาดสถานการณ์การใช้งาน
คลาสสาธารณะ casdemo {ส่วนตัว int final int thread_num = 1,000; INT สุดท้ายส่วนตัว max_value = 20000000; Atomicinteger ส่วนตัว Casi = Atomicinteger ใหม่ (0); private int synci = 0; Private String Path = "/ผู้ใช้/pingping/datacenter/books/linux/linux commands.txt"; โมฆะสาธารณะ casadd () พ่น InterruptedException {long start = system.currentTimeMillis (); เธรด [] เธรด = เธรดใหม่ [thread_num]; สำหรับ (int i = 0; i <thread_num; i ++) {เธรด [i] = เธรดใหม่ (ใหม่ runnable () {public void run () {ในขณะที่ (casi.get () <max_value) {casi.getandincrement ();}}}); เธรด [i]. start (); } สำหรับ (int j = 0; j <thread_num; j ++) {เธรด [j] .oin (); } system.out.println ("CAS ค่าใช้จ่ายเวลา:" + (System.currentTimeMillis () - เริ่มต้น)); } โมฆะสาธารณะ syncadd () พ่น InterruptedException {long start = system.currentTimeMillis (); เธรด [] เธรด = เธรดใหม่ [thread_num]; สำหรับ (int i = 0; i <thread_num; i ++) {เธรด [i] = เธรดใหม่ (ใหม่ runnable () {โมฆะสาธารณะเรียกใช้ () {ในขณะที่ (synci <max_value) {ซิงโครไนซ์ ("synci") {++ synci;}}}}}); เธรด [i]. start (); } สำหรับ (int j = 0; j <thread_num; j ++) เธรด [j] .oin (); System.out.println ("เวลาซิงค์เวลา:" + (System.currentTimeMillis () - เริ่มต้น)); -การทำงานบนซีพียูคู่หลักของฉันผลลัพธ์มีดังนี้:
จะเห็นได้ว่าภายใต้เธรดที่แตกต่างกันเวลาที่ใช้ในการใช้การคำนวณ CAS นั้นมากกว่าของการซิงโครไนซ์ เหตุผลคือบรรทัดที่ 15
14 ในขณะที่ (casi.get () <max_value) {15 casi.getandincrement (); 16}การดำเนินการเป็นการดำเนินการที่ใช้เวลานานมาก หลังจากดำเนินการ 15 บรรทัดลูปจะถูกป้อนทันทีและการดำเนินการจะดำเนินต่อไปส่งผลให้เกิดความขัดแย้งในเธรดที่ร้ายแรง
3. การปรับปรุงสถานการณ์การใช้ CAS
เพื่อที่จะแก้ปัญหาข้างต้นจำเป็นต้องทำให้เวลาในการดำเนินการของแต่ละลูปนานขึ้นนั่นคือมันสามารถลดความขัดแย้งของเธรดได้อย่างมาก แก้ไขรหัสดังนี้:
คลาสสาธารณะ casdemo {ส่วนตัว int final int thread_num = 1,000; INT สุดท้าย INT MAX_VALUE = 1000; Atomicinteger ส่วนตัว Casi = Atomicinteger ใหม่ (0); private int synci = 0; Private String Path = "/ผู้ใช้/pingping/datacenter/books/linux/linux คำสั่งทั่วไปโดยละเอียด reperation.txt"; โมฆะสาธารณะ CASADD2 () พ่น InterruptedException {Long Begin = System.currentTimeMillis (); เธรด [] เธรด = เธรดใหม่ [thread_num]; สำหรับ (int i = 0; i <thread_num; i ++) {เธรด [i] = เธรดใหม่ (ใหม่ runnable () {public void run () {ในขณะที่ (casi.get () <max_value) {casi.getandincrement (); ลอง e) {E.PrintStackTrace ();}}}}}); เธรด [i]. start (); } สำหรับ (int j = 0; j <thread_num; j ++) เธรด [j] .oin (); System.out.println ("CAS สุ่มค่าใช้จ่ายเวลา:" + (System.currentTimeMillis () - เริ่มต้น)); } โมฆะสาธารณะ syncAdd2 () พ่น InterruptedException {Long Begin = System.CurrentTimeMillis (); เธรด [] เธรด = เธรดใหม่ [thread_num]; สำหรับ (int i = 0; i <thread_num; i ++) {เธรด [i] = เธรดใหม่ (ใหม่ runnable () {public void run () {ในขณะที่ (synci <max_value) {ซิงโครไนซ์ ("synci") {++ synci; } catch (ioexception e) {e.printstacktrace ();}}}}); เธรด [i]. start (); } สำหรับ (int j = 0; j <thread_num; j ++) เธรด [j] .oin (); System.out.println ("เวลาซิงค์เวลา:" + (System.currentTimeMillis () - เริ่มต้น)); -ในขณะที่ลูปการดำเนินการเพื่ออ่านเนื้อหาไฟล์จะถูกเพิ่มซึ่งใช้เวลาประมาณ 40ms ซึ่งจะช่วยลดความขัดแย้งของเธรด ผลการทดสอบมีดังนี้:
จะเห็นได้ว่าเมื่อความขัดแย้งของทรัพยากรมีขนาดค่อนข้างเล็กวิธี CAS และประสิทธิภาพการซิงโครไนซ์ซิงโครไนซ์จะคล้ายกัน ทำไม CAS ไม่บรรลุประสิทธิภาพที่สูงกว่าการซิงโครไนซ์?
JDK ที่ใช้ในการทดสอบคือ 1.7 เริ่มต้นจาก jdk1.6 มีการปรับให้เหมาะสมจำนวนมากได้รับการแนะนำให้รู้จักกับการใช้งานล็อคเช่นล็อคที่เกิดขึ้นการขจัดล็อคล็อคการล็อคน้ำหนักเบาล็อคลำเอียงการหมุนแบบปรับตัวและเทคโนโลยีอื่น ๆ เพื่อลดค่าใช้จ่ายของการล็อค หลักการของการล็อคสปินนั้นคล้ายกับการหมุนของ CAS และได้รับการปรับให้เหมาะสมกว่าการหมุน CAS สำหรับรายละเอียดโปรดดูกลไกการล็อค JVM เชิงลึก 1-synchronized
4. สรุป
1. เมื่อใช้ CAS เมื่อความขัดแย้งของเธรดร้ายแรงประสิทธิภาพของโปรแกรมจะลดลงอย่างมาก CAS เหมาะสำหรับสถานการณ์ที่มีความขัดแย้งในเธรดน้อยลง
2. การซิงโครไนซ์ได้รับการปรับปรุงและปรับให้เหมาะสมหลังจาก JDK1.6 การใช้งานพื้นฐานของการซิงโครไนซ์ส่วนใหญ่ขึ้นอยู่กับคิวของการล็อคฟรี แนวคิดพื้นฐานคือการปิดกั้นหลังจากสปินให้แข่งขันต่อเพื่อล็อคหลังจากสลับการแข่งขันการเสียสละความยุติธรรมเล็กน้อย แต่ได้รับปริมาณงานสูง เมื่อมีความขัดแย้งของเธรดน้อยลงประสิทธิภาพที่คล้ายกันสามารถรับได้ เมื่อมีความขัดแย้งในเธรดร้ายแรงประสิทธิภาพจะสูงกว่าของ CAS มาก
บทสรุปข้างต้นของการเขียนโปรแกรมพร้อมกันของ Java - การใช้ CAS อย่างระมัดระวังเป็นคำอธิบายโดยละเอียดของบรรณาธิการ ฉันหวังว่ามันจะให้ข้อมูลอ้างอิงและฉันหวังว่าคุณจะสนับสนุน wulin.com มากขึ้น