โดยทั่วไปแล้วความเร็วของงานการผลิตมากกว่าความเร็วในการบริโภค คำถามของรายละเอียดคือความยาวของคิวและวิธีการจับคู่ความเร็วในการผลิตและการบริโภค
โมเดลผู้ผลิตผู้ผลิตทั่วไปมีดังนี้:
สำหรับการผลิตทั่วไปเร็วกว่าการบริโภค เมื่อคิวเต็มเราไม่ต้องการให้งานใดถูกเพิกเฉยหรือไม่ดำเนินการในเวลานี้ผู้ผลิตสามารถรอสักครู่ก่อนที่จะส่งงาน . ส่งงานต่อไปเมื่อคิวไม่เต็มดังนั้นจึงไม่มีเวลาว่าง การปิดกั้นเป็นเรื่องง่าย
นอกจากนี้เมื่อคิวว่างเปล่าผู้บริโภคไม่สามารถรับงานได้พวกเขาสามารถรอสักครู่ก่อนที่จะได้รับ . แนะนำให้ใช้วิธีการโทร ด้วยวิธีนี้เมื่อผู้ผลิตหยุดการผลิตจริงผู้บริโภคจะไม่รออย่างไม่สิ้นสุด
ดังนั้นรูปแบบการผลิตและการบริโภคที่มีประสิทธิภาพที่รองรับการปิดกั้นจึงถูกนำมาใช้
เดี๋ยวก่อนเนื่องจาก JUC ช่วยให้เราใช้พูลเธรดทำไมเรายังต้องใช้ชุดของสิ่งนี้? ไม่สะดวกกว่าที่จะใช้ ExecutorService โดยตรงหรือไม่?
ลองมาดูโครงสร้างพื้นฐานของ Threadpoolexecutor:
แต่ปัญหาคือแม้ว่าคุณจะระบุการปิดกั้นคิวด้วยตนเองเมื่อสร้าง Threadpoolexecutor ในความเป็นจริงเมื่อคิวเต็มวิธีการดำเนินการจะไม่บล็อก
การคัดลอกรหัสมีดังนี้:
โมฆะสาธารณะดำเนินการ (คำสั่งเรียกใช้) {
if (command == null)
โยน nullpointerexception ใหม่ ();
if (poolsize> = corepoolsize ||! addifundercorepoolsize (คำสั่ง)) {
if (runstate == Running && workqueue.offer (คำสั่ง)) {
if (runstate! = running || poolsize == 0)
ตรวจสอบให้แน่ใจว่ามีการจัดการ (คำสั่ง);
-
อื่นถ้า (! addifundermaximumpoolsize (คำสั่ง))
ปฏิเสธ (คำสั่ง);
-
-
ในเวลานี้สิ่งที่ต้องทำเพื่อให้ได้ผลลัพธ์: เมื่อผู้ผลิตส่งงานและคิวเต็มผู้ผลิตสามารถบล็อกและรองานที่จะบริโภค
กุญแจสำคัญคือในสภาพแวดล้อมที่เกิดขึ้นพร้อมกันคิวเต็มไม่สามารถตัดสินได้โดยผู้ผลิตและ Threadpoolexecutor.getqueue (). size () ไม่สามารถเรียกใช้เพื่อตรวจสอบว่าคิวเต็มหรือไม่
ในการดำเนินการของสระว่ายน้ำเธรดเมื่อคิวเต็มรูปแบบปฏิเสธการใช้งาน Handler ที่ผ่านเข้ามาในระหว่างการก่อสร้างจะถูกเรียกให้ปฏิเสธการประมวลผลของงาน การใช้งานเริ่มต้นคือ abortpolicy ซึ่งจะส่งโดยตรงที่ถูกปฏิเสธ executionException
ฉันจะไม่ลงรายละเอียดเกี่ยวกับกลยุทธ์การปฏิเสธหลายประการที่นี่ การบริโภค
การคัดลอกรหัสมีดังนี้:
คลาสสแตติกระดับสาธารณะ Callerrunspolicy ใช้ DENGEDEXECUTIONDHANDLER {
-
* สร้าง <tt> callerrunspolicy </tt>
-
Public Callerrunspolicy () {}
-
* ดำเนินการงาน R ในเธรดของผู้โทรเว้นแต่ผู้ดำเนินการ
* ถูกปิดตัวลงซึ่งในกรณีนี้งานจะถูกยกเลิก
* @param r งานที่เรียกใช้งานได้ร้องขอให้ดำเนินการ
* @param e ผู้ดำเนินการพยายามทำงานนี้
-
โมฆะสาธารณะปฏิเสธการตรวจสอบ (runnable r, threadpoolexecutor e) {
ถ้า (! e.isshutdown ()) {
r.run ();
-
-
-
อย่างไรก็ตามกลยุทธ์นี้ยังมีอันตรายที่ซ่อนอยู่ ดำเนินงานต่อไป
อ้างถึงความคิดที่คล้ายกันวิธีที่ง่ายที่สุดเราสามารถกำหนด DensedExecutionHandler ได้โดยตรงและเปลี่ยนเพื่อเรียก blockingqueue.put เมื่อคิวเต็มเพื่อให้ตระหนักถึงการบล็อกของผู้ผลิต:
การคัดลอกรหัสมีดังนี้:
ใหม่ DENECTEDExecutionHandler () {
@Override
โมฆะสาธารณะปฏิเสธการตรวจสอบ (Runnable R, threadpoolexecutor executor) {
if (! executor.isshutdown ()) {
พยายาม {
executor.getqueue (). ใส่ (r);
} catch (interruptedException e) {
// ไม่ควรถูกขัดจังหวะ
-
-
-
-
ด้วยวิธีนี้เราไม่จำเป็นต้องใส่ใจเกี่ยวกับตรรกะของคิวและผู้บริโภคอีกต่อไป
เมื่อเทียบกับการออกแบบดั้งเดิมวิธีนี้สามารถลดปริมาณรหัสและสามารถหลีกเลี่ยงปัญหามากมายในสภาพแวดล้อมที่เกิดขึ้นพร้อมกัน แน่นอนว่าคุณสามารถใช้วิธีการอื่นเช่นการใช้ semaphores เป็นขีด จำกัด การเข้ามาเมื่อส่ง แต่ถ้าคุณต้องการบล็อกผู้ผลิตมันจะซับซ้อน