Java มีเธรดพิเศษ ซึ่งก็คือเธรด daemon ซึ่งมีลำดับความสำคัญต่ำมากและจะถูกดำเนินการเมื่อเธรดอื่นในโปรแกรมเดียวกันไม่ได้ดำเนินการเท่านั้น
เนื่องจากเธรด daemon มีคุณสมบัติเหล่านี้ โดยทั่วไปจึงใช้เพื่อจัดเตรียมบริการสำหรับเธรดทั่วไป (หรือเรียกว่าเธรดผู้ใช้) ในโปรแกรม โดยทั่วไปจะมีการวนซ้ำไม่สิ้นสุด หรือใช้เพื่อรอการร้องขอบริการ หรือเพื่อดำเนินการงาน ฯลฯ พวกเขาไม่สามารถทำงานที่สำคัญใดๆ ได้เนื่องจากเราไม่แน่ใจว่าจะได้รับการจัดสรรเวลา CPU เมื่อใด และจะยุติการทำงานโดยอัตโนมัติเมื่อไม่มีเธรดอื่นทำงานอยู่ แอปพลิเคชันทั่วไปของเธรดประเภทนี้คือการรวบรวมขยะ Java
ในตัวอย่างนี้ในส่วนนี้ เราจะสร้างสองเธรด เธรดแรกเป็นเธรดปกติ ซึ่งเขียนเหตุการณ์ลงในคิว และอีกเธรดคือเธรด daemon ซึ่งจะล้างเหตุการณ์ในคิวและลบเหตุการณ์ที่มีอยู่นานกว่า 10 วินาที
รู้ว่ามัน
ทำตามขั้นตอนด้านล่างเพื่อใช้งานโปรแกรมตัวอย่าง
1. สร้างคลาสเหตุการณ์ซึ่งใช้เพื่อบันทึกข้อมูลเหตุการณ์ที่จำเป็นสำหรับการทำงานของโปรแกรมเท่านั้น ประกาศคุณสมบัติสองประการ คุณสมบัติหนึ่งคือคุณสมบัติ date ของประเภท java.util.Date และอีกคุณสมบัติหนึ่งคือคุณสมบัติเหตุการณ์ของประเภท String จากนั้นสร้างวิธีการอ่านและเขียนสำหรับคุณสมบัติทั้งสองนี้ รหัสมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
กิจกรรมชั้นเรียนสาธารณะ {
วันที่ส่วนตัว วันที่;
เหตุการณ์สตริงส่วนตัว
วันที่สาธารณะ getDate() {
วันที่เดินทางกลับ;
-
โมฆะสาธารณะ setDate (วันที่) {
this.date = วันที่;
-
สตริงสาธารณะ getEvent() {
เหตุการณ์การกลับมา;
-
โมฆะสาธารณะ setEvent (เหตุการณ์สตริง) {
this.event = เหตุการณ์;
-
-
2. สร้างคลาสชื่อ WriterTask และใช้อินเทอร์เฟซ Runnable รหัสมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
WriterTask คลาสสาธารณะใช้ Runnable {
3. ประกาศแอตทริบิวต์คิวที่ใช้ในการจัดเก็บเหตุการณ์ ใช้ตัวสร้างคลาส และใช้พารามิเตอร์เพื่อเริ่มต้นแอตทริบิวต์คิว รหัสมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
Deque <เหตุการณ์> deque ส่วนตัว;
WriterTask สาธารณะ (Deque <Event> deque) {
this.deque = deque;
-
4. ใช้เมธอด run() ของงานนี้ ซึ่งมีการวนซ้ำที่เคลื่อนที่ 100 ครั้ง ในการสำรวจแต่ละครั้ง ออบเจ็กต์เหตุการณ์ใหม่จะถูกสร้างขึ้น จากนั้นบันทึกลงในคิว และพักเป็นเวลา 1 วินาที รหัสมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
@แทนที่
โมฆะสาธารณะวิ่ง () {
สำหรับ (int i = 0; i < 100; i++) {
เหตุการณ์เหตุการณ์ = เหตุการณ์ใหม่ ();
event.setDate(วันที่ใหม่());
event.setEvent(String.format("เธรด %s ได้สร้างเหตุการณ์แล้ว",
Thread.currentThread().getId()));
deque.addFirst(เหตุการณ์);
พยายาม {
TimeUnit.SECONDS.sleep (1);
} จับ (InterruptedException e) {
e.printStackTrace();
-
-
-
5. สร้างคลาสชื่อ CleanerTask และสืบทอดคลาส Thread รหัสมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
CleanerTask คลาสสาธารณะขยายเธรด {
6. ประกาศแอตทริบิวต์คิวที่ใช้ในการจัดเก็บเหตุการณ์ ใช้ตัวสร้างคลาส และใช้พารามิเตอร์เพื่อเริ่มต้นแอตทริบิวต์คิว ในวิธีการก่อสร้าง ให้ตั้งค่าเธรดเป็นเธรด daemon โดยการเรียกเมธอด setDaemon() รหัสมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
Deque <เหตุการณ์> deque ส่วนตัว;
CleanerTask สาธารณะ (Deque <Event> deque) {
this.deque = deque;
setDaemon(จริง);
-
7. ใช้เมธอด run() มีการวนซ้ำไม่สิ้นสุดในเนื้อความของเมธอดเพื่อรับเวลาปัจจุบัน จากนั้นจึงเรียกเมธอด clearn() รหัสมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
@แทนที่
โมฆะสาธารณะวิ่ง () {
ในขณะที่ (จริง) {
วันที่ วันที่ = วันที่ใหม่ ();
สะอาด (วันที่);
-
-
8. ใช้เมธอด clean() ในวิธีนี้ ให้รับเวลาล่าสุด จากนั้นตรวจสอบความแตกต่างของเวลาระหว่างเวลาและเวลาปัจจุบัน หากถูกสร้างขึ้นเมื่อ 10 วินาทีที่แล้ว ให้ลบเหตุการณ์ปัจจุบัน แล้วตรวจสอบครั้งถัดไป เหตุการณ์. หากกิจกรรมถูกลบ ข้อมูลเกี่ยวกับเหตุการณ์ที่ถูกลบจะถูกพิมพ์ออกมา และความยาวล่าสุดของคิวก็จะถูกพิมพ์ออกมาด้วย เพื่อให้สามารถสังเกตความคืบหน้าในการดำเนินการของโปรแกรมได้ รหัสมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
โมฆะส่วนตัวสะอาด (วันที่) {
ความแตกต่างที่ยาวนาน
ลบบูลีน;
ถ้า (deque.size() == 0) {
กลับ;
-
ลบ = เท็จ;
ทำ {
เหตุการณ์ e = deque.getLast();
ความแตกต่าง = date.getTime() - e.getDate().getTime();
ถ้า (ผลต่าง > 10,000) {
System.out.printf("ตัวล้างข้อมูล: %s/n", e.getDate());
deque.removeLast();
ลบ = จริง;
-
} ในขณะที่ (ผลต่าง > 10,000);
ถ้า (ลบ) {
System.out.printf("Clearner: ขนาดของคิว: %d/n", deque.size());
-
-
9. สร้างคลาสหลักของโปรแกรม ซึ่งเป็นคลาส Main จากนั้นจึงนำเมธอด main() ไปใช้ รหัสมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
ชั้นเรียนสาธารณะหลัก {
โมฆะคงที่สาธารณะ main (String [] args) {
10. ใช้คลาส Deque เพื่อสร้างคิวเพื่อจัดเก็บกิจกรรม รหัสมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
Deque<เหตุการณ์> deque = ArrayDeque ใหม่<>();
11. สร้างและเริ่มเธรด WriterTask สามเธรดและเธรด CleanerTask หนึ่งเธรด รหัสมีดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
Deque<เหตุการณ์> deque = ArrayDeque ใหม่<>();
นักเขียน WriterTask = WriterTask ใหม่ (deque);
สำหรับ (int i = 0; i <3; i++) {
เธรดเธรด = เธรดใหม่ (ผู้เขียน);
เธรด.เริ่มต้น();
-
CleanerTask ตัวล้าง = CleanerTask ใหม่ (deque);
ทำความสะอาดเริ่มต้น();
12. รันโปรแกรมและดูผลการดำเนินการ
รู้ว่าทำไม
เมื่อวิเคราะห์ผลการดำเนินการของโปรแกรม เราจะเห็นว่าคิวแรกเพิ่มขึ้นเป็น 30 จากนั้นจึงเปลี่ยนระหว่าง 27 ถึง 30 จนกว่าการทำงานของโปรแกรมจะสิ้นสุดลง
โปรแกรมจะเริ่มดำเนินการจากเธรด WriterTask สามเธรดก่อน แต่ละเธรดจะเพิ่มเหตุการณ์ลงในคิวก่อน จากนั้นจึงเข้าสู่โหมดสลีปเป็นเวลา 1 วินาที หลังจากผ่านไป 10 วินาทีแรก จะมีเหตุการณ์สามสิบเหตุการณ์ในคิว ในช่วง 10 วินาทีนี้ เมื่อเธรด WriterTask ทั้งสามเธรดอยู่ในโหมดสลีป เธรด CleanerTask จะทำงานด้วย แต่ไม่มีเหตุการณ์ใดจะถูกลบ เนื่องจากเวลาการสร้างของเหตุการณ์ทั้งหมดไม่เกิน 10 วินาที หลังจาก 10 วินาทีแรก WriterTask สามรายการจะเพิ่มสามเหตุการณ์ในคิวทุกๆ วินาที ในทำนองเดียวกัน CleanerTask จะลบสามเหตุการณ์ทุกๆ วินาที ดังนั้น จำนวนเหตุการณ์อยู่ระหว่าง 27 ถึง 30
เมื่อเธรด WriterTask ทั้งหมดอยู่ในโหมดสลีป เรามีอิสระในการประมวลผลเวลา โดยปล่อยให้เธรด daemon ทำงานในช่วงเวลานี้ หากคุณตั้งค่าเวลาพักของเธรด WriterTask ให้สั้นลง เธรด CleanerTask จะได้รับเวลาการทำงานของ CPU น้อยลง หากเป็นกรณีนี้ ความยาวของคิวจะยังคงขยายต่อไปเนื่องจากเธรด CleanerTask ไม่เคยได้รับเวลาทำงานเพียงพอที่จะลบเหตุการณ์ที่เพียงพอ
ไม่มีวันสิ้นสุด
เธรดสามารถตั้งค่าเป็นเธรด daemon ได้โดยการเรียกเมธอด setDaemon() ก่อนที่จะเรียกเมธอด start() เมื่อเธรดเริ่มทำงาน สถานะ daemon จะไม่สามารถแก้ไขได้
คุณยังสามารถใช้ isDaemon() เพื่อตรวจสอบว่าเธรดเป็นเธรด daemon หรือไม่ หากเป็นเธรด daemon จะส่งคืนค่าจริง หากเป็นเธรดปกติจะส่งคืนค่าเท็จ
ใช้หลักคำสอน
บทความนี้แปลมาจาก "Java 7 Concurrency Cookbook" (D Gua Ge ขโมยมาในชื่อ "Java7 Concurrency Example Collection") และใช้เป็นสื่อการเรียนรู้เท่านั้น ห้ามนำไปใช้เพื่อวัตถุประสงค์ทางการค้าใดๆ โดยไม่ได้รับอนุญาต
ความสำเร็จเล็กๆ น้อยๆ
โค้ดตัวอย่างทั้งหมดที่ใช้ในส่วนนี้เวอร์ชันสมบูรณ์
กรอกโค้ดของคลาสกิจกรรมให้สมบูรณ์
คัดลอกรหัสรหัสดังต่อไปนี้:
แพ็คเกจ com.diguage.books.concurrencycookbook.chapter1.recipe7;
นำเข้า java.util.Date;
-
*คลาสข้อมูลเหตุการณ์
* วันที่: 19-09-2556
* เวลา: 22:56 น
-
กิจกรรมชั้นเรียนสาธารณะ {
วันที่ส่วนตัว วันที่;
เหตุการณ์สตริงส่วนตัว
วันที่สาธารณะ getDate() {
วันที่เดินทางกลับ;
-
โมฆะสาธารณะ setDate (วันที่) {
this.date = วันที่;
-
สตริงสาธารณะ getEvent() {
เหตุการณ์การกลับมา;
-
โมฆะสาธารณะ setEvent (เหตุการณ์สตริง) {
this.event = เหตุการณ์;
-
-
รหัสที่สมบูรณ์ของคลาส WriterTask
คัดลอกรหัสรหัสดังต่อไปนี้:
แพ็คเกจ com.diguage.books.concurrencycookbook.chapter1.recipe7;
นำเข้า java.util.Date;
นำเข้า java.util.Deque;
นำเข้า java.util.concurrent.TimeUnit;
-
* สร้างเหตุการณ์ทุกวินาที
* วันที่: 19-09-2556
* เวลา: 22:59 น
-
WriterTask คลาสสาธารณะใช้ Runnable {
Deque <เหตุการณ์> deque ส่วนตัว;
WriterTask สาธารณะ (Deque <Event> deque) {
this.deque = deque;
-
@แทนที่
โมฆะสาธารณะวิ่ง () {
สำหรับ (int i = 0; i < 100; i++) {
เหตุการณ์เหตุการณ์ = เหตุการณ์ใหม่ ();
event.setDate(วันที่ใหม่());
event.setEvent(String.format("เธรด %s ได้สร้างเหตุการณ์แล้ว",
Thread.currentThread().getId()));
deque.addFirst(เหตุการณ์);
พยายาม {
TimeUnit.SECONDS.sleep (1);
} จับ (InterruptedException e) {
e.printStackTrace();
-
-
-
-
รหัสที่สมบูรณ์ของคลาส CleanerTask
คัดลอกรหัสรหัสดังต่อไปนี้:
แพ็คเกจ com.diguage.books.concurrencycookbook.chapter1.recipe7;
นำเข้า java.util.Date;
นำเข้า java.util.Deque;
-
* การล้างเหตุการณ์
* วันที่: 19-09-2556
* เวลา: 23:33 น
-
CleanerTask คลาสสาธารณะขยายเธรด {
Deque <เหตุการณ์> deque ส่วนตัว;
CleanerTask สาธารณะ (Deque <Event> deque) {
this.deque = deque;
setDaemon(จริง);
-
@แทนที่
โมฆะสาธารณะวิ่ง () {
ในขณะที่ (จริง) {
วันที่ วันที่ = วันที่ใหม่ ();
สะอาด (วันที่);
-
-
-
* ลบกิจกรรม
-
* @param วันที่
-
โมฆะส่วนตัวสะอาด (วันที่) {
ความแตกต่างที่ยาวนาน
ลบบูลีน;
ถ้า (deque.size() == 0) {
กลับ;
-
ลบ = เท็จ;
ทำ {
เหตุการณ์ e = deque.getLast();
ความแตกต่าง = date.getTime() - e.getDate().getTime();
ถ้า (ผลต่าง > 10,000) {
System.out.printf("ตัวล้างข้อมูล: %s/n", e.getDate());
deque.removeLast();
ลบ = จริง;
-
} ในขณะที่ (ผลต่าง > 10,000);
ถ้า (ลบ) {
System.out.printf("Clearner: ขนาดของคิว: %d/n", deque.size());
-
-
-
รหัสที่สมบูรณ์ของคลาสหลัก
คัดลอกรหัสรหัสดังต่อไปนี้:
แพ็คเกจ com.diguage.books.concurrencycookbook.chapter1.recipe7;
นำเข้า java.util.ArrayDeque;
นำเข้า java.util.Deque;
-
* วันที่: 19-09-2556
* เวลา: 23:54 น
-
ชั้นเรียนสาธารณะหลัก {
โมฆะคงที่สาธารณะ main (String [] args) {
Deque<เหตุการณ์> deque = ArrayDeque ใหม่<>();
นักเขียน WriterTask = WriterTask ใหม่ (deque);
สำหรับ (int i = 0; i <3; i++) {
เธรดเธรด = เธรดใหม่ (ผู้เขียน);
เธรด.เริ่มต้น();
-
CleanerTask ตัวล้าง = CleanerTask ใหม่ (deque);
ทำความสะอาดเริ่มต้น();
-
-