ด้วยการพัฒนาอินเทอร์เน็ตที่แข็งแกร่ง บริษัท อินเทอร์เน็ตจำนวนมากกำลังเผชิญกับปัญหาด้านความปลอดภัยที่เกิดจากการขยายตัวของปริมาณผู้ใช้ บทความนี้มุ่งเน้นไปที่กลไกการล็อคทั่วไปหลายประการในการพร้อมกันของ Java
1. ล็อคบวก
การล็อคลำเอียงเป็นกลไกการเพิ่มประสิทธิภาพการล็อคที่เสนอโดย JDK1.6 แนวคิดหลักคือหากโปรแกรมไม่แข่งขันการดำเนินการซิงโครไนซ์เธรดที่ได้รับก่อนหน้านี้การล็อคจะถูกยกเลิก กล่าวคือหากมีการล็อคโดยเธรดมันจะเข้าสู่โหมดอคติ เมื่อเธรดร้องขอล็อคอีกครั้งไม่จำเป็นต้องดำเนินการซิงโครไนซ์ที่เกี่ยวข้องซึ่งจะช่วยประหยัดเวลาการทำงาน หากเธรดอื่นทำการขอล็อคในระหว่างโหมดล็อคออกจากโหมดอคติ ใช้ -xx:+usebiasedlocking ใน JVM
แพ็คเกจ jvmproject; นำเข้า java.util.list; นำเข้า java.util.vector; คลาสสาธารณะลำเอียง {รายการคงที่สาธารณะ <จำนวนเต็ม> numberList = เวกเตอร์ใหม่ <integer> (); โมฆะคงที่สาธารณะหลัก (สตริง [] args) {long start = system.currentTimeMillis (); จำนวน int = 0; int startNum = 0; ในขณะที่ (นับ <10,00000000) {numberlist.add (startnum); StartNum+= 2; นับ ++; } Long End = System.currentTimeMillis (); System.out.println (end-begin); -เริ่มต้นเวกเตอร์เพิ่มวัตถุจำนวนเต็ม 100,000,000 รายการลงไปแล้วส่งออกความแตกต่างของเวลา สิ่งนี้ใช้เพื่อทดสอบประสิทธิภาพของล็อคลำเอียง ทำไมคุณควรใช้เวกเตอร์แทน arraylist?
เนื่องจาก arraylist เป็นเธรดที่ไม่ปลอดภัยเวกเตอร์จึงปลอดภัยเธรด ซึ่งอาจไม่เฉพาะเจาะจงเพียงพอคุณสามารถดูที่ซอร์สโค้ด
การดำเนินการเกือบทั้งหมดในเวกเตอร์จะถูก sychronized ในขณะที่ arraylist ไม่ได้ดังนั้นเวกเตอร์จึงปลอดภัยด้าย
ถัดไปลองทดสอบว่าการเปิดล็อคแบบลำเอียงและไม่เปิดล็อคลำเอียงมีต่อประสิทธิภาพของโปรแกรม
กำหนดค่าพารามิเตอร์การเริ่มต้น JVM (เปิดการล็อคอคติ) เป็น:
กำหนดค่าพารามิเตอร์การเริ่มต้น JVM (ปิดการล็อคอคติ) เป็น:
สมบูรณ์แบบ! เวลาทำงานของโปรแกรมที่ช่วยให้ล็อคลำเอียงสั้นลงอย่างมาก มันมีข้อดีบางประการในการเปิดใช้งานล็อคลำเอียงมากกว่าที่จะไม่เปิดใช้งานล็อคลำเอียง วิธีการซิงโครไนซ์ของการใช้งานวัตถุในเธรดเดียว ในความเป็นจริงมันสามารถเข้าใจได้ด้วยวิธีนี้ เมื่อมีเธรดเดียวที่ใช้งานวัตถุเวกเตอร์ด้วยวิธีการซิงโครไนซ์การดำเนินการบนเวกเตอร์จะถูกแปลงเป็นการดำเนินการใน ArrayList
การล็อคแบบเอนเอียงไม่มีผลการปรับให้เหมาะสมอย่างมากเมื่อการล็อคมีการแข่งขันเนื่องจากการแข่งขันจำนวนมากจะทำให้เธรดถือล็อคเพื่อสลับอย่างต่อเนื่องและเป็นเรื่องยากสำหรับการล็อคที่จะยังคงอยู่ในโหมดลำเอียง ในเวลานี้การใช้การล็อคแบบเอนเอียงไม่เพียง แต่ไม่สามารถเพิ่มประสิทธิภาพประสิทธิภาพได้ แต่อาจลดประสิทธิภาพของระบบ ดังนั้นในกรณีของการแข่งขันที่ดุเดือดคุณสามารถลองใช้งานได้
-xx: -usebiastedlocking พารามิเตอร์ปิดใช้งานการล็อคอคติ
2. ล็อคน้ำหนักเบา
หากการล็อคลำเอียงล้มเหลวเครื่องเสมือน Java จะขอให้เธรดใช้สำหรับการล็อคน้ำหนักเบา การล็อคน้ำหนักเบาถูกนำไปใช้ภายในเครื่องเสมือนและใช้งานโดยใช้วัตถุที่กลายเป็น basicobjectlock ซึ่งประกอบด้วยวัตถุ basiclock และตัวชี้วัตถุ Java ที่ถือล็อค วัตถุ BasicObjectLock ถูกวางไว้ในกรอบ Java Stack ฟิลด์ที่แสดง _header ยังคงอยู่ในวัตถุ BasicLock ซึ่งใช้ในการสำรองคำว่าเครื่องหมายของส่วนหัวของวัตถุ
เมื่อเธรดถือล็อคของวัตถุข้อมูลเครื่องหมายคำส่วนหัวของวัตถุมีดังนี้
[PTR | 00] ล็อค
บิตสองบิตในตอนท้ายคือ 00 และคำทำเครื่องหมายทั้งหมดเป็นตัวชี้ไปยังวัตถุ BasicLock เนื่องจากวัตถุ BasicObjectLock อยู่ในสแต็กเธรดตัวชี้จะต้องชี้ไปที่พื้นที่สแต็กเธรดที่ถือล็อค เมื่อมีความจำเป็นต้องพิจารณาว่าเธรดถือวัตถุหรือไม่ก็จำเป็นที่จะต้องพิจารณาว่าตัวชี้ของส่วนหัวของวัตถุนั้นอยู่ในช่วงที่อยู่สแต็กของเธรดปัจจุบันหรือไม่ ในเวลาเดียวกันจอแสดงผลที่แสดงของวัตถุ BasicLock สำรองเนื้อหาคำทำเครื่องหมายของวัตถุต้นฉบับและฟิลด์ OBJ ของวัตถุ BasicObjectLock ชี้ไปที่หัวของวัตถุที่ถือล็อค
3. ล็อคเฮฟวี่เวท
เมื่อล็อคน้ำหนักเบาล้มเหลวเครื่องเสมือนจะใช้ล็อคเฮฟวี่เวท เมื่อใช้ล็อคเฮฟวี่เวทคำทำเครื่องหมายของวัตถุมีดังนี้:
[PTR | 10] จอภาพ
ในระหว่างการดำเนินการเธรดอาจถูกระงับที่ระดับระบบปฏิบัติการ ถ้าเป็นเช่นนั้นค่าใช้จ่ายในการสลับและการโทรระหว่างเธรดจะเพิ่มขึ้นอย่างมาก
4. สปินล็อค
สปินล็อคสามารถทำให้เธรดไม่หยุดเมื่อไม่ได้รับการล็อค แต่แทนที่จะสลับเพื่อเรียกใช้ลูปเปล่า (นั่นคือการหมุนที่เรียกว่าซึ่งหมายถึงการดำเนินการวนลูปว่างเปล่า) หากเธรดสามารถรับล็อคได้หลังจากลูปว่างเปล่าหลายครั้งมันจะดำเนินการต่อไป หากเธรดยังไม่สามารถรับล็อคได้ก็จะถูกระงับ
หลังจากใช้สปินล็อคโอกาสของเธรดที่ถูกระงับจะลดลงค่อนข้างมากและความสอดคล้องของการดำเนินการเธรดนั้นค่อนข้างเพิ่มขึ้น ดังนั้นจึงมีความสำคัญเชิงบวกบางประการสำหรับเธรดที่เกิดขึ้นพร้อมกันซึ่งไม่ได้แข่งขันกับล็อคและมีช่วงเวลาสั้น ๆ อย่างไรก็ตามสำหรับโปรแกรมที่เกิดขึ้นพร้อมกันที่มีการแข่งขันอย่างรุนแรงกับล็อคและล็อคแบบเธรดเดี่ยวใช้เวลานานการล็อคสปินมักจะไม่สามารถรับล็อคที่สอดคล้องกันได้หลังจากรอสปิน สิ่งนี้ไม่เพียงเสียเวลา CPU เท่านั้น แต่ยังมีการดำเนินการที่ถูกระงับในที่สุดอย่างหลีกเลี่ยงไม่ได้ แต่ยังเสียทรัพยากรระบบด้วย
ใน JDK1.6 เครื่องเสมือน Java ให้พารามิเตอร์ -xx:+useSpinning เพื่อเปิดใช้งานการล็อคสปินและใช้พารามิเตอร์ -xx: preblockspin เพื่อตั้งค่าจำนวนครั้งที่สปินล็อครอ
เริ่มต้นจาก JDK 1.7 พารามิเตอร์ของสปินล็อคจะถูกยกเลิก เครื่องเสมือนไม่รองรับการล็อคสปินที่ผู้ใช้กำหนดค่าใช้จ่ายอีกต่อไป สปินล็อคจะถูกเรียกใช้งานเสมอและจำนวนของการล็อคสปินจะถูกปรับโดยอัตโนมัติโดยเครื่องเสมือน