1. ภาพรวม
การใช้งานฟังก์ชั่นของการดำเนินงานอย่างสม่ำเสมอใน Java ส่วนใหญ่ใช้คลาสสองคลาสคือคลาส Timer และ Timertask ตัวจับเวลาใช้เพื่อดำเนินการงานที่ระบุในเธรดพื้นหลังตามแผนที่ระบุ
Timertask เป็นคลาสนามธรรมและคลาสย่อยของมันแสดงถึงงานที่สามารถวางแผนได้โดยตัวจับเวลา รหัสเฉพาะที่จะดำเนินการถูกเขียนในวิธีการเรียกใช้ที่ต้องใช้ TimerTask
2. มาดูตัวอย่างที่ง่ายที่สุด
มาอธิบายผ่านรหัส
นำเข้า java.text.simpledateFormat; นำเข้า java.util.date; นำเข้า java.util.timer; นำเข้า java.util.timertask; คลาสสาธารณะ timerdemo {สตริงคงที่สาธารณะ getCurrentTime () {วันที่ = วันที่ใหม่ (วันที่ใหม่ (); SimpledateFormat SDF = New SimpledateFormat ("YYYY-MM-DD HH: MM: SS"); ส่งคืน sdf.format (วันที่); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น InterruptedException {system.out.println ("เริ่มต้นหลัก:"+getCurrentTime ()); startTimer (); thread.sleep (1,000*5); // sleep เป็นเวลา 5 วินาที system.out.println ("Main End:"+getCurrentTime ()); } โมฆะคงที่สาธารณะ startTimer () {timertask task = new timertask () {@Override โมฆะสาธารณะเรียกใช้ () {system.out.println ("งานรัน:"+getCurrentTime ()); - ตัวจับเวลาตัวจับเวลา = ตัวจับเวลาใหม่ (); timer.schedule (งาน, 0); -เพื่ออำนวยความสะดวกให้กับข้อมูลการสังเกตโดยการพิมพ์เราได้เพิ่มข้อมูลการพิมพ์ลงในวิธีหลักและเรียกว่า thread.sleep เพื่อให้การนอนหลับหลัก นอกจากนี้ยังมีการเพิ่มวิธี getCurrentTime ในคลาสเพื่อรับวันที่ปัจจุบัน
ในรหัสข้างต้นในวิธี startTimer วัตถุ TimerTask (งานที่จะดำเนินการโดยตัวจับเวลา) ถูกสร้างขึ้นและสร้างวัตถุตัวจับเวลาและวิธีการกำหนดเวลาของคลาสจับเวลาถูกเรียก คลาสจับเวลามีวิธีการกำหนดตารางเวลาหลายวิธีที่มีพารามิเตอร์ที่แตกต่างกัน สิ่งที่ใช้ที่นี่คือ:
ตารางโมฆะสาธารณะ (งาน TimerTask ล่าช้านาน)
ความหมายของวิธีนี้คือการดำเนินงานหลังจากจับเวลาจะล่าช้า (มิลลิวินาที) เวลา หากความล่าช้าเป็นลบหรือ 0 งานจะดำเนินการทันที และเป็นงานดำเนินการครั้งเดียวและงานจะไม่ถูกทำซ้ำ (หรือกำหนดเวลา) ในภายหลัง
สำหรับคลาสจับเวลาจะมีวิธีการที่มีฟังก์ชั่นเดียวกันดังนี้:
ตารางโมฆะสาธารณะ (งาน TimerTask เวลาวันที่)
ความแตกต่างระหว่างวิธีนี้และวิธีการข้างต้นคือวิธีการข้างต้นระบุว่าการดำเนินการล่าช้าเป็นระยะเวลาหนึ่งและวิธีนี้ระบุว่าการดำเนินการจะดำเนินการในเวลาที่กำหนด โปรดทราบว่าหากเวลาปัจจุบันของระบบเกินเวลาที่กำหนดโดยเวลาพารามิเตอร์งานจะถูกดำเนินการทันที
เมื่อเรียกใช้รหัสด้านบนเราพบว่าโปรแกรมจะพิมพ์ข้อมูลสองชิ้นทันทีคล้ายกับต่อไปนี้:
การเริ่มต้นหลัก: 2016-01-13 22:23:18
งานรัน: 2016-01-13 22:23:18
เนื่องจากค่าพารามิเตอร์การหน่วงเวลาที่เราส่งผ่านไปยังวิธีการกำหนดเวลาที่นี่คือ 0 งานจะถูกดำเนินการทันทีดังนั้นเวลาในการพิมพ์คำสั่งทั้งสองจึงเหมือนกันซึ่งเป็นสิ่งที่ควรจะเป็น คุณสามารถเปลี่ยนค่าความล่าช้าที่เข้ามาด้วยตัวเองเพื่อดูการเปลี่ยนแปลงในข้อมูลผลลัพธ์ หลังจากนั้นประมาณ 5 วินาที (เช่นเวลานอน) ฉันยังคงพิมพ์ข้อความ 1 ข้อความ:
จุดจบหลัก: 2016-01-13 22:23:23
เวลาสำหรับการพิมพ์ข้อมูลคือ 5 วินาทีสั้น ๆ จากคำสั่งข้างต้นซึ่งสอดคล้องกับการตั้งค่าการนอนหลับซึ่งก็สมเหตุสมผลมาก
แต่เราจะพบปรากฏการณ์ที่น่าสนใจมากและเราจะพบว่ากระบวนการจะไม่ออก ในเวลานี้เธรดหลักได้สิ้นสุดลงแล้ว ซึ่งหมายความว่าหลังจากตัวจับเวลาทำงานให้เสร็จสมบูรณ์แม้ว่าจะไม่มีงานรอที่จะดำเนินการในภายหลังเธรดพื้นหลังที่สร้างขึ้นในตัวจับเวลาจะไม่ออกทันที ฉันตรวจสอบเอกสาร Java Doc ที่เกี่ยวข้องและอธิบายว่าเธรดตัวจับเวลาจะไม่ออกอย่างแข็งขันและจำเป็นต้องรอการรวบรวมขยะ แต่คอลเลกชันขยะของ Java ไม่สามารถควบคุมได้ด้วยรหัสเอง แต่ถูกควบคุมโดยเครื่องเสมือน
หลังจากการวิจัยพบว่าเมื่อสร้างวัตถุตัวจับเวลาและดำเนินการตัวจับเวลาตัวจับเวลา = ตัวจับเวลาใหม่ (); คำสั่งเธรดตัวจับเวลาจะถูกสร้างขึ้น กล่าวอีกนัยหนึ่งแม้ว่ารหัสข้างต้นจะไม่มีตัวจับเวลา schedule (งาน, 0); คำสั่งโปรแกรมจะไม่ออก ฉันรู้สึกว่านี่ค่อนข้างไม่มีเหตุผล ฉันศึกษาซอร์สโค้ดของคลาสจับเวลาอีกครั้งและพบว่ามันยังมีตัวสร้างที่มีพารามิเตอร์บูลีน:
ตัวจับเวลาสาธารณะ (บูลีน Isdaemon)
อย่างที่คุณเห็นจากชื่อพารามิเตอร์หากค่าพารามิเตอร์เป็นจริงเธรดตัวจับเวลาที่สร้างโดยตัวจับเวลาคือเธรด daemon ความหมายของเธรด daemon คือเมื่อเธรดคนงานทั้งหมดในทางออกกระบวนการ Java เธรด Daemon จะออกโดยอัตโนมัติ
ในเวลานี้เราเพียงแค่ต้องเปลี่ยนรหัสสำหรับการสร้างวัตถุตัวจับเวลาในตัวอย่างข้างต้นเป็น: ตัวจับเวลาตัวจับเวลา = ตัวจับเวลาใหม่ (จริง);
หลังจากที่คุณพบว่าโปรแกรมทำงานแล้วโปรแกรมจะออกหลังจากเธรดหลัก (เธรดหลักไม่ใช่เธรด daemon แต่เธรดคนงาน) จะเสร็จสมบูรณ์ซึ่งหมายความว่าเธรดตัวจับเวลาก็ออกซึ่งหมายความว่าหลังจากเพิ่มพารามิเตอร์จริง
แต่ปัญหาคือในสถานการณ์แอปพลิเคชันจริงมีเธรดคนงานจำนวนมากที่ทำงานอยู่และโปรแกรมจะไม่ออกจากกันอย่างไม่เป็นทางการ แล้วถ้าคุณต้องการให้ตัวจับเวลาออกหรือปิดทันที เราจะแนะนำสิ่งนี้ด้านล่าง
3. ออกจากตัวจับเวลา
คลาสจับเวลามีวิธีการยกเลิกเพื่อยกเลิกตัวจับเวลา การเรียกวิธีการยกเลิกจะยุติการจับเวลานี้และยกเลิกงานที่กำหนดไว้ทั้งหมดในปัจจุบัน สิ่งนี้ไม่รบกวนงานการดำเนินการในปัจจุบัน (ถ้ามีอยู่) เมื่อตัวจับเวลาถูกยกเลิกเธรดการดำเนินการของมันจะสิ้นสุดลงและไม่สามารถกำหนดงานได้อีกต่อไป
โปรดทราบว่าโดยการเรียกใช้วิธีนี้ภายในวิธีการเรียกใช้ของงานตัวจับเวลาที่เรียกว่าตัวจับเวลานี้คุณสามารถตรวจสอบให้แน่ใจว่างานที่ดำเนินการเป็นงานสุดท้ายที่ดำเนินการโดยตัวจับเวลานี้ วิธีนี้สามารถเรียกได้ซ้ำ ๆ อย่างไรก็ตามการโทรครั้งที่สองและครั้งต่อไปนั้นไม่ถูกต้อง
ลองดูที่รหัสตัวอย่างอื่น:
นำเข้า java.text.simpledateFormat; นำเข้า java.util.date; นำเข้า java.util.timer; นำเข้า java.util.timertask; คลาสสาธารณะ timerdemo {สตริงคงที่สาธารณะ getCurrentTime () {วันที่ = วันที่ใหม่ (วันที่ใหม่ (); SimpledateFormat SDF = New SimpledateFormat ("YYYY-MM-DD HH: MM: SS"); ส่งคืน sdf.format (วันที่); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น InterruptedException {system.out.println ("เริ่มต้นหลัก:"+getCurrentTime ()); ตัวจับเวลาตัวจับเวลา = startTimer (); thread.sleep (1,000*5); // sleep เป็นเวลา 5 วินาที system.out.println ("Main End:"+getCurrentTime ()); timer.cancel (); } public timer startTimer () {timertask task = new timertask () {@Override โมฆะสาธารณะเรียกใช้ () {system.out.println ("งานรัน:"+getCurrentTime ()); - ตัวจับเวลาตัวจับเวลา = ตัวจับเวลาใหม่ (); timer.schedule (งาน, 0); ตัวจับเวลากลับ; - การรันโปรแกรมนั้นเหมือนกับผลลัพธ์ของตัวอย่างด้านบน ความแตกต่างคือเมื่อวิธีหลักสิ้นสุดลง กระบวนการจะออกอย่างแข็งขันซึ่งหมายความว่าเธรดตัวจับเวลาถูกปิด
เพราะเราเรียกวิธีการยกเลิกในวิธีหลัก โปรดทราบว่าหากคุณไม่ได้เรียกวิธีการยกเลิกในวิธีการเรียกใช้ของ Timertask ให้แน่ใจว่างานที่คุณต้องการดำเนินการได้เริ่มต้นหรือเสร็จสิ้นมิฉะนั้นหากงานไม่ได้เริ่มดำเนินการ เพียงแค่เรียกยกเลิกและงานทั้งหมดจะไม่ถูกดำเนินการ ตัวอย่างเช่นรหัสด้านบน
ตัวอย่างเช่นในรหัสข้างต้นหากเราไม่เรียกวิธีการยกเลิกในวิธีหลัก แต่เพิ่มตัวจับเวลา SCHEDULE (TASK, 0); คำสั่งในวิธี startTimer และเพิ่มตัวจับเวลา cancel (); คำสั่งหลังจากทำงานคุณจะพบว่างานจับเวลาจะไม่ถูกดำเนินการเนื่องจากจะถูกยกเลิกก่อนที่การดำเนินการจะเสร็จสมบูรณ์
4. ดำเนินงานเป็นประจำ
ในตัวอย่างข้างต้นเรากำลังแนะนำงานครั้งเดียวนั่นคือเวลาจับเวลามาถึงแล้ว หลังจากดำเนินการงานแล้วมันจะไม่ถูกทำซ้ำในภายหลัง ในแอปพลิเคชันจริงมีหลายสถานการณ์ที่ต้องใช้งานเดียวกันเพื่อดำเนินการซ้ำ ๆ เป็นประจำ มีสองสถานการณ์: หนึ่งคือการดำเนินงานทุกครั้งและอีกสถานการณ์หนึ่งคือการปฏิบัติงานในเวลาที่กำหนด (หรือหลาย) คะแนนทุกวัน (หรือรายสัปดาห์รายเดือน ฯลฯ )
ก่อนอื่นให้ดูที่กรณีแรกซึ่งเป็นตัวอย่างของการดำเนินงานเดียวกันทุก ๆ 10 วินาที รหัสมีดังนี้:
นำเข้า java.text.simpledateFormat; นำเข้า java.util.date; นำเข้า java.util.timer; นำเข้า java.util.timertask; คลาสสาธารณะ timerdemo {สตริงคงที่สาธารณะ getCurrentTime () {วันที่ = วันที่ใหม่ (วันที่ใหม่ (); SimpledateFormat SDF = New SimpledateFormat ("YYYY-MM-DD HH: MM: SS"); ส่งคืน sdf.format (วันที่); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น InterruptedException {system.out.println ("เริ่มต้นหลัก:"+getCurrentTime ()); startTimer (); } โมฆะคงที่สาธารณะ startTimer () {timertask task = new timertask () {@Override โมฆะสาธารณะเรียกใช้ () {system.out.println ("งานรัน:"+getCurrentTime ()); ลอง {thread.sleep (1,000*3); } catch (interruptedException e) {e.printStackTrace (); - ตัวจับเวลาตัวจับเวลา = ตัวจับเวลาใหม่ (); timer.schedule (งาน, 1,000*5,1000*10); - ดำเนินการโปรแกรมข้างต้นและข้อมูลเอาต์พุตมีดังนี้ (เนื่องจากตัวจับเวลาไม่หยุดและงานซ้ำแล้วซ้ำอีกเอาต์พุตจะถูกส่งออกอย่างต่อเนื่องเพียงบางส่วนของผลลัพธ์ก่อนหน้านี้เท่านั้น
การเริ่มต้นหลัก: 2016-01-14 08:41:14
งานรัน: 2016-01-14 08:41:19
งานรัน: 2016-01-14 08:41:29
งานรัน: 2016-01-14 08:41:39
งานรัน: 2016-01-14 08:41:49
งานรัน: 2016-01-14 08:42:00
งานรัน: 2016-01-14 08:42:10
งานรัน: 2016-01-14 08:42:20
งานรัน: 2016-01-14 08:42:30 น
งานรัน: 2016-01-14 08:42:40
ในรหัสข้างต้นเราเรียก Timer.schedule (งาน, 1,000*5,1000*10); ซึ่งหมายความว่างานล่าช้า 5 วินาทีจากนั้นจะทำซ้ำทุก ๆ 10 วินาที เราสังเกตว่าเวลาการพิมพ์ในข้อมูลผลลัพธ์เหมือนกับที่คาดไว้ นอกจากนี้จะเห็นได้ว่าช่วงเวลาจะถูกคำนวณตามเวลาเริ่มงานนั่นคือไม่ต้องรออีก 10 วินาทีหลังจากงานเสร็จ
คลาสจับเวลามีสองวิธีในการใช้งานฟังก์ชั่นดังกล่าวดังนี้:
ตารางโมฆะสาธารณะ (งาน TimerTask, ล่าช้าระยะยาว, ระยะเวลานาน) กำหนดการสาธารณะ (งาน TimerTask, วันที่ครั้งแรก, ระยะเวลานาน)
วิธีแรกที่เราใช้ด้านบนรหัส ความแตกต่างระหว่างสองวิธีคือเวลาของการดำเนินการครั้งแรก วิธีแรกจะถูกดำเนินการหลังจากความล่าช้าที่ระบุของระยะเวลา (เป็นมิลลิวินาที); วิธีที่สองจะถูกดำเนินการที่จุดเวลาที่กำหนด
ในเวลานี้เราพิจารณาสถานการณ์ต่อไปนี้ หากเวลาดำเนินการของงานเกินเวลารอครั้งต่อไปจะเกิดอะไรขึ้น ลองดูรหัส:
นำเข้า java.text.simpledateFormat; นำเข้า java.util.date; นำเข้า java.util.timer; นำเข้า java.util.timertask; คลาสสาธารณะ timerdemo {สตริงคงที่สาธารณะ getCurrentTime () {วันที่ = วันที่ใหม่ (วันที่ใหม่ (); SimpledateFormat SDF = New SimpledateFormat ("YYYY-MM-DD HH: MM: SS"); ส่งคืน sdf.format (วันที่); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น InterruptedException {system.out.println ("เริ่มต้นหลัก:"+getCurrentTime ()); startTimer (); } โมฆะคงที่สาธารณะ startTimer () {timertask task = new timertask () {@Override โมฆะสาธารณะเรียกใช้ () {system.out.println ("งานเริ่มต้น:"+getCurrentTime ()); ลอง {thread.sleep (1,000*10); } catch (interruptedException e) {e.printStackTrace (); } system.out.println ("Task End:"+getCurrentTime ()); - ตัวจับเวลาตัวจับเวลา = ตัวจับเวลาใหม่ (); timer.schedule (งาน, 1,000*5,1000*5); - เมื่อเทียบกับรหัสก่อนหน้าเราเปลี่ยนรหัส 2 รหัสเท่านั้นและแก้ไขการพิมพ์ หนึ่งคือการเปลี่ยนการนอนหลับในวิธีการเรียกใช้เป็น 10 วินาทีและอื่น ๆ คือการเปลี่ยนรอบการดำเนินการของงานเป็น 5 วินาที กล่าวอีกนัยหนึ่งเวลาดำเนินการของงานเกินช่วงเวลาระหว่างการดำเนินการซ้ำ ๆ ของงาน เรียกใช้โปรแกรมผลลัพธ์ก่อนหน้านี้มีดังนี้:
เริ่มต้นหลัก: 2016-01-14 09:03:51
งานเริ่มต้น: 2016-01-14 09:03:56
Task End: 2016-01-14 09:04:06
งานเริ่มต้น: 2016-01-14 09:04:06
Task End: 2016-01-14 09:04:16
งานเริ่มต้น: 2016-01-14 09:04:16
Task End: 2016-01-14 09:04:26
งานเริ่มต้น: 2016-01-14 09:04:26
Task End: 2016-01-14 09:04:36
งานเริ่มต้น: 2016-01-14 09:04:36
Task End: 2016-01-14 09:04:46
งานเริ่มต้น: 2016-01-14 09:04:46
Task End: 2016-01-14 09:04:56
จะเห็นได้ว่าหลังจากดำเนินการแต่ละงานงานถัดไปจะถูกดำเนินการทันที เนื่องจากเวลาที่ใช้ตั้งแต่เริ่มต้นงานจนถึงการทำงานให้เสร็จสมบูรณ์เกินช่วงเวลาระหว่างการทำซ้ำงานการดำเนินการจะเกิดขึ้นซ้ำ
5. ดำเนินงานเป็นประจำ (ทำซ้ำเวลาที่กำหนด)
มาใช้ฟังก์ชั่นดังกล่าวทำงานอย่างสม่ำเสมอเวลา 13.00 น. ทุกวันซึ่งมีฟังก์ชั่นนี้ในหลาย ๆ ระบบเช่นการทำงานที่ใช้เวลานานและใช้เวลานานและใช้ทรัพยากรเช่นการสำรองข้อมูลข้อมูลและสถิติข้อมูลในงานนี้ รหัสมีดังนี้:
นำเข้า java.text.simpledateFormat; นำเข้า java.util.calendar; นำเข้า java.util.date; นำเข้า java.util.timer; นำเข้า java.util.timertask; คลาสสาธารณะ timerdemo {สตริงคงที่ SimpledateFormat SDF = New SimpledateFormat ("YYYY-MM-DD HH: MM: SS"); ส่งคืน sdf.format (วันที่); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น InterruptedException {system.out.println ("เริ่มต้นหลัก:" + getCurrentTime ()); startTimer (); } โมฆะคงที่สาธารณะ startTimer () {timertask task = new timertask () {@Override โมฆะสาธารณะเรียกใช้ () {system.out.println ("งานเริ่มต้น:" + getCurrentTime ()); ลอง {thread.sleep (1,000 * 20); } catch (interruptedException e) {e.printStackTrace (); } system.out.println ("Task End:" + getCurrentTime ()); - ตัวจับเวลาตัวจับเวลา = ตัวจับเวลาใหม่ (); timer.schedule (งาน, buildtime (), 1,000 * 60 * 60 * 24); } วันที่คงที่ส่วนตัว buildtime () {ปฏิทินปฏิทิน = calendar.getInstance (); Calendar.set (Calendar.hour_of_day, 1); Calendar.set (Calendar.minute, 0); Calendar.set (Calendar.second, 0); เวลาวันที่ = calendar.getTime (); ถ้า (เวลาก่อนหน้านี้ (วันที่ใหม่ ())) {// ถ้าเวลาปัจจุบันคือหลังจาก 13.00 น. จำเป็นต้องใช้เวลา 1 วันมิฉะนั้นงานจะถูกดำเนินการทันที // ระบบหลายระบบมักจะต้องทำงานทันทีเมื่อระบบเริ่มต้น แต่พวกเขาจำเป็นต้องดำเนินการในเวลา 13.00 น. ทุกวัน ฉันควรทำอย่างไร? // มันง่ายมากเพียงแค่ดำเนินงานแยกต่างหากเมื่อระบบเริ่มต้นการโทร (ไม่จำเป็นต้องใช้ตัวจับเวลามันเป็นเพียงรหัสในการดำเนินการงานนั้น) เวลา = Addday (เวลา, 1); } เวลากลับ; } วันที่คงที่ส่วนตัว addday (วันที่วัน, วัน int) {ปฏิทิน startdt = calendar.getInstance (); startdt.settime (วันที่); startdt.add (calendar.day_of_month, วัน); return startdt.getTime (); -เนื่องจากมันถูกดำเนินการเป็นระยะเวลา 24 ชั่วโมงจึงเป็นไปไม่ได้ที่จะรอการสังเกตของผลลัพธ์
6. สรุป
บทความนี้แนะนำกลไกของวิธีการทำงานที่กำหนดเวลาโดยใช้คลาส Java Timer จะเห็นได้ว่ายังมีอีกหลายวิธีในการให้ความสนใจ ในตัวอย่างที่แนะนำในบทความนี้แต่ละตัวจับเวลาสอดคล้องกับงานเดียวเท่านั้น
เนื้อหาที่แนะนำในบทความนี้สามารถตอบสนองสถานการณ์แอปพลิเคชันส่วนใหญ่ได้ แต่ยังมีปัญหาบางอย่างเช่นรวมถึงงานหลายอย่างสำหรับการจับเวลา? ฉันสามารถเพิ่มงานอีกครั้งหลังจากยกเลิกตัวจับเวลาได้หรือไม่? มีวิธีอื่นใดบ้างในคลาส Timer? คำถามเหล่านี้จะถูกนำเสนอในโพสต์บล็อกต่อไปนี้
ลิงค์ดั้งเดิม: http://www.cnblogs.com/51kata/p/5128745.html
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น