ข้อความ
เมื่อการเขียนโปรแกรมในสภาพแวดล้อมที่เกิดขึ้นพร้อมกันจำเป็นต้องใช้กลไกการล็อคเพื่อซิงโครไนซ์ระหว่างหลายเธรดเพื่อให้แน่ใจว่าการเข้าถึงทรัพยากรที่ใช้ร่วมกันโดยเฉพาะ การล็อคอาจทำให้เกิดความเสียหายด้านประสิทธิภาพซึ่งดูเหมือนจะเป็นที่รู้จักกันดี อย่างไรก็ตามการล็อคตัวเองไม่ได้นำการใช้ประสิทธิภาพมากและประสิทธิภาพส่วนใหญ่เป็นกระบวนการของการรับล็อคในเธรด หากมีเธรดเดียวที่แข่งขันกันเพื่อล็อคและไม่มีการแข่งขันแบบมัลติเธรดในเวลานี้ JVM จะปรับให้เหมาะสมและการใช้ประสิทธิภาพที่เกิดจากการล็อคสามารถถูกละเว้นโดยทั่วไป ดังนั้นการกำหนดมาตรฐานการทำงานของการล็อคการเพิ่มประสิทธิภาพวิธีการใช้งานของการล็อคและหลีกเลี่ยงการแข่งขันเธรดที่ไม่จำเป็นไม่เพียง แต่สามารถปรับปรุงประสิทธิภาพของโปรแกรมได้ แต่ยังหลีกเลี่ยงความเป็นไปได้ของการปิดกั้นด้ายที่เกิดจากการล็อคผิดปกติและปรับปรุงความทนทานของโปรแกรม ต่อไปนี้อธิบายแนวคิดการเพิ่มประสิทธิภาพล็อคหลายประการ
1. พยายามอย่าล็อควิธีการ
เมื่อมีการเพิ่มล็อคลงในฟังก์ชั่นสมาชิกปกติเธรดจะได้รับการล็อควัตถุของวัตถุที่มีวิธีการอยู่ ในเวลานี้วัตถุทั้งหมดจะถูกล็อค นอกจากนี้ยังหมายความว่าหากวิธีการซิงโครไนซ์หลายวิธีที่ให้ไว้โดยวัตถุนี้มีไว้สำหรับบริการที่แตกต่างกันจากนั้นเนื่องจากวัตถุทั้งหมดถูกล็อคเมื่อดำเนินธุรกิจหนึ่งรายการเธรดธุรกิจที่ไม่เกี่ยวข้องอื่น ๆ จะต้องรอด้วย ตัวอย่างต่อไปนี้แสดงสิ่งนี้:
คลาส Lockmethod มีวิธีการซิงโครไนซ์สองวิธีซึ่งเรียกว่าในสองกระบวนการทางธุรกิจ:
LockMethod คลาสสาธารณะ {public synchronized void busia () {สำหรับ (int i = 0; i <10,000; i ++) {system.out.println (thread.currentthread (). getName ()+"จัดการกับธุรกิจ A:"+i); }} void busib () {สำหรับ (int i = 0; i <10,000; i ++) {system.out.println (thread.currentthread (). getName ()+"จัดการกับธุรกิจ b:"+i); -Bussa เป็นคลาสเธรดที่ใช้ในการจัดการธุรกิจและเรียกวิธีการล็อค busia () ของ lockmethod:
Public Class Bussb ขยายเธรด {LockMethod LockMethod; เป็นโมฆะดีล (LockMethod LockMethod) {this.lockMethod = LockMethod; } @Override โมฆะสาธารณะ Run () {super.run (); lockmethod.busib (); -TestLockMethod Class ใช้เธรด bussa และ bussb สำหรับการประมวลผลธุรกิจ:
Public Class TestlockMethod ขยายเธรด {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {lockmethod lockmethod = new LockMethod (); bussa bussa = ใหม่ bussa (); BUSSB BUSSB = New BUSSB (); bussa.deal (lockmethod); bussb.deal (lockmethod); bussa.start (); bussb.start (); -เมื่อเรียกใช้โปรแกรมคุณจะเห็นว่าในระหว่างการดำเนินการของเธรด bussa, bussb ไม่สามารถเข้าสู่ฟังก์ชั่น bussib () เนื่องจากล็อควัตถุล็อคโมเดอร์ได้รับโดยเธรด bussa
2. ลดบล็อกรหัสแบบซิงโครนัสและล็อคเฉพาะข้อมูล
บางครั้งเพื่อความสะดวกในการเขียนโปรแกรมบางคนซิงโครไนซ์รหัสชิ้นใหญ่ หากการดำเนินการบางอย่างในบล็อกรหัสนี้ไม่เกี่ยวข้องกับทรัพยากรที่ใช้ร่วมกันพวกเขาควรวางไว้นอกบล็อกซิงโครนัสเพื่อหลีกเลี่ยงการล็อคถือเป็นเวลานานทำให้เธรดอื่น ๆ ยังคงอยู่ในสถานะรอ โดยเฉพาะอย่างยิ่งการดำเนินการรอบและการดำเนินการ I/O แบบซิงโครนัส ไม่เพียง แต่หมายถึงการลดบล็อกการซิงโครไนซ์ในช่วงบรรทัดของรหัส แต่ยังอยู่ในตรรกะการดำเนินการบล็อกการซิงโครไนซ์ควรลดลง ตัวอย่างเช่นเพิ่มการตัดสินตามเงื่อนไขมากขึ้นและซิงโครไนซ์หากพวกเขาตรงตามเงื่อนไขแทนที่จะดำเนินการตัดสินตามเงื่อนไขหลังจากการซิงโครไนซ์เพื่อลดตรรกะที่ไม่จำเป็นเข้าสู่บล็อกการซิงโครไนซ์
3. พยายามอย่ารวมล็อคไว้ในล็อค
สถานการณ์นี้มักเกิดขึ้น หลังจากเธรดได้รับการล็อคแล้วจะเรียกวิธีการซิงโครไนซ์ของวัตถุอื่นในบล็อกวิธีการซิงโครไนซ์และรับล็อคที่สอง สิ่งนี้อาจนำไปสู่คำขอล็อคหลายครั้งในสแต็กการโทร ในกรณีของมัลติเธรดอาจทำให้เกิดความซับซ้อนและยากต่อการวิเคราะห์ข้อยกเว้นส่งผลให้เกิดการหยุดชะงัก รหัสต่อไปนี้แสดงสิ่งนี้:
ซิงโครไนซ์ (a) {ซิงโครไนซ์ (b) {}}หรือวิธีการซิงโครไนซ์เรียกว่าในบล็อกการซิงโครไนซ์:
ซิงโครไนซ์ (a) {b b = objarraylist.get (0); B.Method (); // นี่คือวิธีการซิงโครไนซ์}ทางออกคือการกระโดดออกและเพิ่มล็อคและไม่รวมถึงการล็อค:
{b b = null; ซิงโครไนซ์ (a) {b = objarraylist.get (0); } B.Method ();} 4. แปรรูปล็อคและจัดการล็อคภายใน
ปลอดภัยกว่าที่จะใช้ล็อคเป็นวัตถุส่วนตัวและไม่สามารถรับได้จากภายนอก วัตถุอาจถูกล็อคโดยตรงโดยเธรดอื่น ๆ และเธรดถือวัตถุล็อควัตถุของวัตถุตัวอย่างเช่น:
คลาส A {โมฆะสาธารณะวิธีการ 1 () {}} คลาส B {โมฆะสาธารณะวิธีการ 1 () {a = ใหม่ a (); ซิงโครไนซ์ (a) {// ล็อคโดยตรง A.Method1 (); -ในวิธีการใช้งานนี้การล็อควัตถุของวัตถุ A ถูกจัดขึ้นโดยภายนอกดังนั้นจึงเป็นอันตรายมากขึ้นที่จะปล่อยให้การล็อคถูกใช้ในหลายสถานที่ด้านนอกและยังทำให้ปัญหาในการอ่านการไหลแบบตรรกะของรหัส วิธีที่ดีกว่าคือการจัดการล็อคตัวเองภายในชั้นเรียนและให้การดำเนินการซิงโครไนซ์ผ่านอินเทอร์เฟซเมื่อจำเป็นต้องใช้รูปแบบการซิงโครนัสภายนอก:
คลาส A {วัตถุส่วนตัวล็อค = วัตถุใหม่ (); โมฆะสาธารณะวิธีการ 1 () {ซิงโครไนซ์ (ล็อค) {}}} คลาส B {โมฆะสาธารณะวิธีการ 1 () {a a = ใหม่ a (); A.Method1 (); - 5. ทำการสลายตัวล็อคที่เหมาะสม
พิจารณาขั้นตอนต่อไปนี้:
Public Class Gameserver {แผนที่สาธารณะ <String, list <player>> tables = new hashmap <string, list <player>> (); โมฆะสาธารณะเข้าร่วม (ผู้เล่นผู้เล่นตารางตาราง) {ถ้า (player.getAccountBalance ()> table.getLimit ()) {ซิงโครไนซ์ (ตาราง) {รายการ <glay> TablePlayers = tables.get (table.getId ()); if (tablePlayers.size () <9) {TablePlayers.Add (ผู้เล่น); }}}}} การปล่อยโมฆะสาธารณะ (ผู้เล่นผู้เล่นตารางตาราง) {/*omit*/} โมฆะสาธารณะ createTable () {/*omit*/} โมฆะสาธารณะ destroytable (ตารางตาราง) {/*omit*/}}}}ในตัวอย่างนี้วิธีการเข้าร่วมจะใช้การล็อคซิงโครไนซ์เพียงครั้งเดียวเพื่อรับรายการรายการ <glay> ในตารางจากนั้นพิจารณาว่าจำนวนผู้เล่นน้อยกว่า 9 ถ้าเป็นเช่นนั้นเพิ่มผู้เล่นหนึ่งคน เมื่อมีรายการ <ผู้เล่นหลายพันรายการในตารางการแข่งขันสำหรับล็อคตารางจะดุเดือดมาก ที่นี่เราสามารถพิจารณาการย่อยสลายล็อค: หลังจากดึงข้อมูลออกไปอย่างรวดเร็วล็อครายการรายการ <glay> เพื่อให้เธรดอื่นสามารถแข่งขันได้อย่างรวดเร็วเพื่อรับ Tables Object Lock:
Gameserver ชั้นเรียนสาธารณะ {
แผนที่สาธารณะ <สตริง
รายการ <ผู้เล่น >> tables = new hashmap <string,
รายการ <ผู้เล่น >> ();
โมฆะสาธารณะเข้าร่วม (ผู้เล่นผู้เล่นตารางตาราง) {
if (player.getAccountBalance ()> table.getLimit ()) {
รายการ <play> TablePlayers = NULL;
ซิงโครไนซ์ (ตาราง) {
TablePlayers = tables.get (table.getId ());
-
ซิงโครไนซ์ (TablePlayers) {
if (tableplayers.size () <9) {
Tableplayers.add (ผู้เล่น);
-
-
-
-
การลาโมฆะสาธารณะ (ผู้เล่นผู้เล่นตารางตาราง) {
/*ละเว้น*/
-
โมฆะสาธารณะ createTable () {
/*ละเว้น*/
-
โมฆะสาธารณะ destroyTable (ตารางตาราง) {
/*ละเว้น*/
-
-