บทความนี้ส่วนใหญ่ศึกษาประเด็นที่เกี่ยวข้องกับหัวข้อพื้นหลังใน Java ดังนี้
ฉันไม่เคยได้ยินมาก่อนว่ามีเธรดพื้นหลังใน Java โดยทั่วไปแล้ว JVM (Java Virtual Machine) โดยทั่วไปจะมีเธรดสองประเภทคือเธรดผู้ใช้และเธรดพื้นหลัง เธรด daemon ที่เรียกว่าหมายถึงเธรดที่ให้บริการทั่วไปในพื้นหลังเมื่อโปรแกรมกำลังทำงานอยู่และเธรดนี้ไม่ได้เป็นส่วนที่ขาดไม่ได้ของโปรแกรม ดังนั้นเมื่อเธรดที่ไม่ใช่พื้นดินทั้งหมดสิ้นสุดลงนั่นคือเมื่อเธรดของผู้ใช้สิ้นสุดลงโปรแกรมจะสิ้นสุดลง ในเวลาเดียวกันมันจะฆ่าเธรดพื้นหลังทั้งหมดในกระบวนการ ในทางกลับกันตราบใดที่เธรดที่ไม่ใช่พื้นดินยังคงทำงานอยู่โปรแกรมจะไม่สิ้นสุด มันจะดีกว่าที่จะเรียกใช้งาน Main () มากกว่าเธรดที่ไม่ใช่แบ็กแบ็ค
ขึ้นอยู่กับคุณสมบัตินี้เมื่อเธรดผู้ใช้ทั้งหมดในทางออกของเครื่องเสมือนจากการรันเธรด Daemon ไม่มีวัตถุบริการ JVM ออก
สิ่งนี้อธิบายไว้ในซอร์สโค้ด JDK
* ทำเครื่องหมายเธรดนี้เป็นเธรด {@linkplain #isdaemon daemon}
* หรือเธรดผู้ใช้ เครื่องเสมือน Java ออกจากเมื่อมีเพียงเครื่องเดียว
* เธรดที่กำลังทำงานอยู่ทั้งหมดเธรด daemon
1. เงื่อนไขสำหรับการเริ่มต้นเธรดพื้นหลัง:
/*เมธอด setDaemon () จะต้องถูกเรียกก่อนเริ่มเธรดเพื่อตั้งค่าเธรดนี้เป็นเธรดพื้นหลัง * ในโปรแกรมนี้หลังจากที่เราป้อนสตริงเธรดหลักจะหยุดทำงาน* จากนั้นไม่มีเธรดสำหรับผู้ใช้ที่สามารถรันในโปรแกรมได้ ดังนั้นเธรดพื้นหลังจะหยุด * JVM จะหยุดลงและผู้อ่านที่สนใจสามารถลองด้วยตัวเอง */คลาสสาธารณะ daemonrunner ใช้งานได้ {@Override โมฆะสาธารณะเรียกใช้ () {ในขณะที่ (จริง) {สำหรับ (int i = 0; i <3; i ++) {system.out.println daemon = เธรดใหม่ (ใหม่ daemonrunner ()); daemon.setdaemon (true); daemon.start (); เครื่องสแกน s = เครื่องสแกนใหม่ (System.in); สตริงสตริง = s.nextline (); runtime.getruntime () ออก "); ลอง {timeunit.milliseconds.sleep (50);} catch (interruptedException e) {e.printstacktrace ();}}});}}2. เธรดทั้งหมดเริ่มต้นในเธรดพื้นหลังเป็นของเธรดพื้นหลัง แม้ว่าคุณจะไม่ได้ระบุอย่างชัดเจนว่าเป็นเธรดพื้นหลัง แต่ก็เป็นเธรดพื้นหลัง
/* คุณสามารถพิจารณาได้ว่าเธรดเป็นเธรดพื้นหลังโดยเรียกใช้วิธี ISDAEMON () หรือไม่ หากเป็นเธรดพื้นหลัง * จากนั้นเธรดใด ๆ ที่สร้างขึ้นจะถูกตั้งค่าโดยอัตโนมัติเป็นเธรดพื้นหลัง * ในตัวอย่างนี้เธรด daemon จะถูกตั้งค่าเป็นโหมดพื้นหลังจากนั้นจะได้รับเธรดเด็กจำนวนมาก เธรดเหล่านี้ไม่ได้ตั้งค่าเป็นโหมดพื้นหลัง * แต่เป็นเธรดพื้นหลัง จากนั้นเธรด daemon จะเข้าสู่ลูปที่ไม่มีที่สิ้นสุดและเรียกใช้วิธีการให้ผลผลิตในลูป* เพื่อส่งผ่านการควบคุมไปยังเธรดหรือกระบวนการอื่น ๆ*/คลาส daemon ใช้งาน runnable {เธรดส่วนตัว [] t = เธรดใหม่ [10];@override public void run () {สำหรับ (int i = 0; i <t.length; i ++) daemonspawn ()); t [i] .start (); system.out.println ("daemonspawn" + i + "เริ่มต้น");} สำหรับ (int i = 0; i <t.length; i ++) {system.out.println ("t [" + i + "] .isdaemon" {thread.yield ();}}} คลาส daemonspawn ใช้งาน runnable {@override โมฆะสาธารณะเรียกใช้ () {ในขณะที่ (จริง) {thread.yield ();}}} daemons คลาสสาธารณะ daemon ()); d.setdaemon (true); d.start (); system.out.println ("d.isdaemon () =" + d.isdaemon ()); ลอง {timeunit.seconds.sleep (1); // ให้เธรดในพื้นหลังเริ่มต้น } catch (interruptedException e) {e.printStackTrace ();}}}ผลการดำเนินการขั้นสุดท้ายมีดังนี้:
d.isdaemon () = true
daemonspawn 0started
daemonspawn 1 started
daemonspawn 2 started
daemonspawn 3 started
Daemonspawn 4started
daemonspawn 5 started
daemonspawn 6started
daemonspawn 7 started
Daemonspawn 8started
Daemonspawn 9started
t [0] .isdaemontrue
t [1] .isdaemontrue
t [2] .isdaemontrue
t [3] .isdaemontrue
t [4] .isdaemontrue
t [5] .isdaemontrue
t [6] .isdaemontrue
t [7] .isdaemontrue
t [8] .isdaemontrue
t [9] .isdaemontrue
3. ระบุวัตถุ ThreadFactory โดยการระบุวิธี Executors.newCachedThreadPool() ด้วยวิธีนี้เราสามารถตั้งค่าเธรดที่เราต้องการเริ่มเป็นเธรดพื้นหลัง
/* ในตัวอย่างนี้สำหรับคอนสตรัคเตอร์แบบคงที่นี้: executors.newcachedThreadpool (ใหม่ daemonthreadfactory ()* เราสามารถส่งผ่านในวัตถุ ThreadFactory ดังนั้นเราจึงสามารถตั้งเธรดที่เราต้องการเริ่มต้นเป็นเธรดพื้นหลังผ่านวิธีนี้* นี่คือการบันทึกใหม่ Thread (R); T.SetDaemon (TRUE); return t;}}/* ในตัวอย่างนี้ในวิธีการหลักวิธีธรรมดาในวิธีการหลักจะถูกเรียกว่า "System.out.println (" Dameons ทั้งหมดเริ่มต้นขึ้น " สายหลักจะสิ้นสุดการวิ่ง (InterruptedException E) {System.out.println ("interrupted");}} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {ExecutorService Exec = Executors.newCachedThreadPool (ใหม่ daemonthreadFactory (); daemonfromfactory ());} system.out.println ("dameons ทั้งหมดเริ่มต้น"); ลอง {timeunit.milliseconds.sleep (500);} catch (interruptedException e) {e.printstacktrace ();}}}}}}}ผลลัพธ์ผลลัพธ์สุดท้ายคือ:
Dameons ทั้งหมดเริ่มต้น
Thread [Thread-3,5, Main] Concurrency.daemonfromfactory@56214c1
Thread [Thread-2,5, Main] Concurrency.daemonfromfactory@5724147D
Thread [Thread-0,5, Main] Concurrency.daemonfromfactory@144fe080
Thread [Thread-1,5, Main] Concurrency.daemonfromfactory@104fa29e
Thread [Thread-8,5, Main] Concurrency.daemonfromfactory@5b069a7f
Thread [Thread-9,5, Main] Concurrency.daemonfromfactory@1a7288d1
Thread [Thread-7,5, Main] Concurrency.daemonfromfactory@25144c3e
Thread [Thread-4,5, Main] Concurrency.daemonfromfactory@288523D
Thread [Thread-6,5, Main] Concurrency.daemonfromfactory@1edae2a8
Thread [Thread-5,5, Main] Concurrency.daemonfromfactory@626007aa
Thread [Thread-3,5, Main] Concurrency.daemonfromfactory@56214c1
Thread [Thread-2,5, Main] Concurrency.daemonfromfactory@5724147D
Thread [Thread-6,5, Main] Concurrency.daemonfromfactory@1edae2a8
Thread [Thread-5,5, Main] Concurrency.daemonfromfactory@626007aa
Thread [Thread-4,5, Main] Concurrency.daemonfromfactory@288523D
Thread [Thread-9,5, Main] Concurrency.daemonfromfactory@1a7288d1
Thread [Thread-7,5, Main] Concurrency.daemonfromfactory@25144c3e
Thread [Thread-8,5, Main] Concurrency.daemonfromfactory@5b069a7f
Thread [Thread-1,5, Main] Concurrency.daemonfromfactory@104fa29e
Thread [Thread-0,5, Main] Concurrency.daemonfromfactory@144fe080
Thread [Thread-2,5, Main] Concurrency.daemonfromfactory@5724147D
Thread [Thread-3,5, Main] Concurrency.daemonfromfactory@56214c1
Thread [Thread-6,5, Main] Concurrency.daemonfromfactory@1edae2a8
Thread [Thread-1,5, Main] Concurrency.daemonfromfactory@104fa29e
Thread [Thread-0,5, Main] Concurrency.daemonfromfactory@144fe080
Thread [Thread-7,5, Main] Concurrency.daemonfromfactory@25144c3e
Thread [Thread-8,5, Main] Concurrency.daemonfromfactory@5b069a7f
Thread [Thread-5,5, Main] Concurrency.daemonfromfactory@626007aa
Thread [Thread-9,5, Main] Concurrency.daemonfromfactory@1a7288d1
Thread [Thread-4,5, Main] Concurrency.daemonfromfactory@288523D
Thread [Thread-2,5, Main] Concurrency.daemonfromfactory@5724147D
Thread [Thread-3,5, Main] Concurrency.daemonfromfactory@56214c1
Thread [Thread-8,5, Main] Concurrency.daemonfromfactory@5b069a7f
Thread [Thread-7,5, Main] Concurrency.daemonfromfactory@25144c3e
Thread [Thread-4,5, Main] Concurrency.daemonfromfactory@288523D
Thread [Thread-6,5, Main] Concurrency.daemonfromfactory@1edae2a8
Thread [Thread-1,5, Main] Concurrency.daemonfromfactory@104fa29e
Thread [Thread-0,5, Main] Concurrency.daemonfromfactory@144fe080
Thread [Thread-9,5, Main] Concurrency.daemonfromfactory@1a7288d1
Thread [Thread-5,5, Main] Concurrency.daemonfromfactory@626007aa
Thread [Thread-3,5, Main] Concurrency.daemonfromfactory@56214c1
Thread [Thread-2,5, Main] Concurrency.daemonfromfactory@5724147D
Thread [Thread-8,5, Main] Concurrency.daemonfromfactory@5b069a7f
4. ก่อนอื่นคุณควรตระหนักว่าหากเธรดผู้ใช้ออกทันทีกระทู้พื้นหลังจะยุติวิธีการเรียกใช้โดยไม่ดำเนินการในประโยคสุดท้าย
/* เมื่อคุณเรียกโปรแกรมนี้คุณจะเห็นว่าประโยคในที่สุดจะไม่ถูกดำเนินการ แต่ถ้าคุณแสดงความคิดเห็นการโทรไปยัง SetDaemon () คุณจะเห็นว่าคำสั่ง* ในที่สุดจะถูกดำเนินการ* พฤติกรรมนี้ถูกต้อง แม้ว่าคุณจะไม่ต้องการพฤติกรรมนี้ตามคำสัญญาที่คุณให้ไว้ต่อหน้าคุณ แต่นี่เป็นกรณี เมื่อเธรดที่ไม่ใช่พื้นดินที่ไม่ได้สิ้นสุดลงเธรดพื้นหลังจะหยุดทันที เนื่องจากเมื่อออกจากหลัก () ออกแล้ว JVM จะปิดเธรด * ทั้งหมดในพื้นหลังทันที เนื่องจากคุณไม่สามารถปิดเธรดพื้นหลังได้อย่างสง่างามจึงเป็นความคิดที่ดี ผู้ดำเนินการที่ไม่ใช่แบ็คเอนด์มักจะเป็นวิธีที่ดีกว่าเพราะงานทั้งหมดที่ควบคุมโดยผู้ดำเนินการสามารถปิดได้ในเวลาเดียวกัน */คลาส Adaemon ใช้งาน runnable {@Override โมฆะสาธารณะเรียกใช้ () {system.out.println ("เริ่ม Adaemon"); ลอง {timeunit.seconds.sleep (1); } catch (interruptedException e) {system.out.println ("ออกผ่าน InterruptedException"); } ในที่สุด {system.out.println ("สิ่งนี้ควรทำงานเสมอ?"); }}} คลาสสาธารณะ daemonsdontrunfinally {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {เธรด t = เธรดใหม่ (ใหม่ adaemon ()); T.Setdaemon (จริง); T.Start (); - ผลลัพธ์ผลลัพธ์สุดท้ายมีดังนี้:
เริ่ม Adaemon
อย่างไรก็ตามหากสถานการณ์กลายเป็นสถานการณ์ต่อไปนี้ผลลัพธ์ผลลัพธ์จะแตกต่างกันอีกครั้ง:
คลาส Adaemon ใช้งาน Runnable {@Override Public Void Run () {System.out.println ("เริ่ม Adaemon"); ลอง {timeunit.seconds.sleep (1); } catch (interruptedException e) {system.out.println ("ออกผ่าน InterruptedException"); } ในที่สุด {system.out.println ("สิ่งนี้ควรทำงานเสมอ?"); }}} คลาสสาธารณะ daemonsdontrunfinally {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {เธรด t = เธรดใหม่ (ใหม่ adaemon ()); T.Setdaemon (จริง); T.Start (); ลอง {timeunit.seconds.sleep (1); } catch (interruptedException e) {e.printStackTrace (); -เนื่องจากเธรดหลักไม่ได้ออกทันทีเธรดพื้นหลังจะได้รับเวลาดำเนินการในระหว่างการนอนหลับของเธรดหลักดังนั้นผลการพิมพ์สุดท้ายคือ:
เริ่ม Adaemon
สิ่งนี้ควรวิ่งเสมอ?
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้เกี่ยวกับการวิเคราะห์อินสแตนซ์เธรดพื้นหลังใน Java และฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงหัวข้ออื่น ๆ ที่เกี่ยวข้องในเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!