เดอะ

“สวัสดี อามีโก้!”

"ฉันต้องการเจาะลึกกับคุณเกี่ยวกับการแจ้งเตือนการรอ วิธีการแจ้งเตือนให้กลไกที่สะดวกสำหรับเธรดในการโต้ตอบ นอกจากนี้ยังสามารถใช้เพื่อสร้างกลไกระดับสูงที่ซับซ้อนสำหรับการโต้ตอบของเธรด"

"ผมจะเริ่มต้นด้วยตัวอย่างเล็กๆ น้อยๆ สมมติว่าเรามีโปรแกรมสำหรับเซิร์ฟเวอร์ที่ต้องทำงานต่างๆ ที่สร้างโดยผู้ใช้ผ่านทางเว็บไซต์ ผู้ใช้สามารถเพิ่มงานต่างๆ โปรเซสเซอร์ -core รับมือได้ เราควรทำงานบนเซิร์ฟเวอร์อย่างไร"

"อย่างแรก เราจะสร้างกลุ่มของเธรดผู้ปฏิบัติงาน มากที่สุดเท่าที่มีคอร์โปรเซสเซอร์ แต่ละเธรดจะสามารถทำงานบนคอร์ของตัวเองได้: เธรดจะไม่รบกวนซึ่งกันและกัน และคอร์โปรเซสเซอร์จะไม่ นั่งเฉยๆ"

"อย่างที่สอง เราจะสร้างคิววัตถุที่จะเพิ่มงานของผู้ใช้ งานประเภทต่างๆ จะสอดคล้องกับวัตถุที่แตกต่างกัน แต่งานทั้งหมดจะใช้อินเทอร์เฟซที่เรียกใช้ได้เพื่อให้สามารถเรียกใช้ได้"

"คุณช่วยยกตัวอย่างวัตถุงานให้ฉันได้ไหม"

"ลองดู:"

คลาสที่คำนวณแฟกทอเรียล n เมื่อมีการเรียกใช้เมธอด run()
class Factorial implements Runnable
{
 public int n = 0;
 public long result = 1;

 public Factorial (int n)
 {
  this.n = n;
 }

 public void run()
 {
  for (int i = 2; i <= n; i++)
   result *= i;
 }
}

"เท่านี้ก็ดีมากแล้ว"

"เยี่ยมมาก ถ้าอย่างนั้นเรามาดูว่าคิวอ็อบเจกต์ควรมีลักษณะอย่างไร คุณจะบอกอะไรฉันได้บ้างเกี่ยวกับเรื่องนี้"

"มันจะต้องปลอดภัยสำหรับเธรด มันถูกโหลดด้วยวัตถุงานโดยเธรดที่รับมาจากผู้ใช้ จากนั้นงานจะถูกหยิบขึ้นมาโดยเธรดของผู้ปฏิบัติงาน"

“ใช่ แล้วถ้าเราหมดงานไปช่วงหนึ่งล่ะ?”

"จากนั้นเธรดคนงานควรรอจนกว่าจะมีมากขึ้น"

"ถูกต้อง ลองจินตนาการว่าทั้งหมดนี้สามารถสร้างได้ในคิวเดียว ลองดูสิ:"

คิวงาน หากไม่มีงานใด ๆ เธรดจะเข้าสู่โหมดสลีปและรอให้งานปรากฏขึ้น:
public class JobQueue
{
 ArrayList jobs = new ArrayList();

 public synchronized void put(Runnable job)
 {
  jobs.add(job);
  this.notifyAll();
 }

 public synchronized Runnable getJob()
 {
  while (jobs.size() == 0)
   this.wait();

  return jobs.remove(0);
 }
}

"เรามี เมธอด getJobที่ตรวจสอบว่ารายการงานว่างเปล่าหรือไม่ จากนั้นเธรดจะเข้าสู่โหมดสลีป (รอ) จนกว่าจะมีบางสิ่งปรากฏขึ้นในรายการ"

"นอกจากนี้ยังมี เมธอด putซึ่งให้คุณเพิ่มงานใหม่ลงในรายการ ทันทีที่เพิ่มงานใหม่ เมธอดalertAllจะถูกเรียก การเรียกเมธอดนี้จะปลุกเธรดผู้ปฏิบัติงานทั้งหมดที่หลับไปในเมธอด getJob"

"จำอีกครั้งได้ไหมว่าวิธีการรอและแจ้งเตือนทำงานอย่างไร"

"เมธอด wait ถูกเรียกภายในบล็อกที่ซิงโครไนซ์บนวัตถุ mutex เท่านั้น ในกรณีของเราสิ่งนี้ ยิ่งกว่านั้น มีสองสิ่งเกิดขึ้น:

1)เธรดหลับ

2)เธรดปล่อย mutex ชั่วคราว (จนกว่าจะตื่นขึ้น)

"หลังจากนั้น เธรดอื่นสามารถเข้าสู่บล็อกที่ซิงโครไนซ์และรับ mutex เดียวกันได้"

" เมธอด alertAllสามารถเรียกได้ภายในบล็อกที่ซิงโครไนซ์ของออบเจกต์ mutex เท่านั้น ในกรณีของเรา: นี่ ยิ่งกว่านั้น มีสองสิ่งเกิดขึ้น:"

1)เธรดทั้งหมดที่รออยู่บนวัตถุ mutex นี้จะถูกปลุกให้ตื่นขึ้น

2) เมื่อเธรดปัจจุบันออกจากบล็อกที่ซิงโครไนซ์ หนึ่งในเธรดที่ปลุกขึ้นมาจะได้รับ mutex และทำงานต่อไป เมื่อปล่อย mutex เธรดอื่นที่ปลุกขึ้นมาจะได้รับ mutex เป็นต้น

"มันคล้ายกับรถบัสมาก คุณเข้ามาและต้องการจ่ายค่าโดยสาร แต่ไม่มีคนขับ ดังนั้นคุณจึง «หลับ» ในที่สุด รถบัสก็เต็ม แต่ก็ยังไม่มีใครจ่ายค่าโดยสารให้ จากนั้นคนขับ มาถึงและพูดว่า «Fare ได้โปรด» และนี่คือจุดเริ่มต้นของ…”

"การเปรียบเทียบที่น่าสนใจ แต่รถบัสคืออะไร"

"ฮูลิโออธิบายเรื่องนี้ มีของแปลกๆ พวกนี้ใช้ในศตวรรษที่ 21"