เพื่อนของฉันขอให้ฉันช่วยฉันเขียนโปรแกรมเพื่อนำเข้าข้อมูลจากเอกสารข้อความไปยังฐานข้อมูล Oracle มันไม่ยากในทางเทคนิค รูปแบบของเอกสารได้รับการแก้ไข ตราบใดที่การวิเคราะห์ฟิลด์ที่สอดคล้องกันในฐานข้อมูลก็เพียงพอแล้วกุญแจสำคัญอยู่ในประสิทธิภาพ
ปริมาณข้อมูลมีขนาดใหญ่และมีระเบียนนับล้าน ดังนั้นเมื่อพิจารณาว่าคุณต้องใช้การดำเนินการหลายเธรดพร้อมกันและคุณพบปัญหาในระหว่างกระบวนการเขียนฉันต้องการนับเวลาทั้งหมดที่ใช้ในกระบวนการเด็กทั้งหมดหลังจากการดำเนินการเสร็จสมบูรณ์ บันทึกเวลาปัจจุบันก่อนที่กระบวนการลูกแรกจะถูกสร้างขึ้น ใช้ System.currentTimeMillis () เพื่อบันทึกเวลาปัจจุบันหลังจากกระบวนการลูกสุดท้ายเสร็จสมบูรณ์ ความแตกต่างของเวลาที่ได้จากการลบสองครั้งคือเวลาทั้งหมด รหัสมีดังนี้
Long TSTART = System.currentTimeMillis (); System.out.println (thread.currentthread (). getName () + "start"); // พิมพ์เครื่องหมายเริ่มต้นสำหรับ (int ii = 0; ii <threadnum; ii ++) {// เปิดเธรด runnable r = new runnable () // ทำอะไรบางอย่าง ... ... System.out.println (thread.currentthread (). getName () + "สิ้นสุด"); }} เธรด t = เธรดใหม่ (r); T.Start (); } system.out.println (thread.currentthread (). getName () + "end."); // พิมพ์ tag end tned long = System.currentTimeMillis (); System.out.println ("เวลาทั้งหมด:" + (แนวโน้ม - tstart) + "ล้าน"); ผลที่ได้คือคำสั่งที่ใช้โดยเธรดหลักในการพิมพ์เวลาทั้งหมดจะถูกดำเนินการเกือบช่วงเวลาที่การวนรอบสำหรับการวนรอบ เหตุผลก็คือเธรดเด็กทั้งหมดจะถูกดำเนินการพร้อมกันและเธรดหลักก็ทำงานเมื่อพวกเขาทำงานซึ่งทำให้เกิดคำถาม: วิธี "ทำให้เธรดหลักรอให้กระทู้เด็กทั้งหมดดำเนินการ" ฉันลองเพิ่ม t.join () หลังจากแต่ละเธรดลูกเริ่มต้นและผลลัพธ์ก็คือเธรดทั้งหมดดำเนินการตามลำดับซึ่งสูญเสียความหมายของการเกิดขึ้นพร้อมกันซึ่งไม่ใช่สิ่งที่ฉันต้องการ
Google ไม่พบวิธีแก้ปัญหาออนไลน์เป็นเวลานาน ไม่มีใครเคยพบกับความต้องการเช่นนี้หรือไม่? หรือปัญหานี้ง่ายเกินไป? Wu Nai ต้องคิดวิธีแก้ปัญหาตัวเอง ...
ในที่สุดโซลูชันของฉันคือการปรับแต่งคลาส ImportThread ที่สืบทอดมาจาก java.lang.thread, overload วิธีการเรียกใช้ () และใช้คุณสมบัติรายการเพื่อบันทึกเธรดที่สร้างขึ้นทั้งหมด ด้วยวิธีนี้ตราบใดที่คุณตัดสินว่ารายการนั้นว่างเปล่าคุณจะรู้ว่ายังมีเธรดลูกที่ยังไม่ได้ดำเนินการหรือไม่ รหัสคลาสมีดังนี้:
ชั้นเรียนสาธารณะ ImportThread ขยายเธรด {รายการคงที่ส่วนตัว <Dread> RunningThreads = new ArrayList <Dred> (); Public ImportThread () {} @Override โมฆะสาธารณะ Run () {การลงทะเบียน (นี่); // ลงทะเบียน System.out.println (thread.currentthread (). getName () + "เริ่ม ... "); // พิมพ์เครื่องหมายเริ่มต้น // "end."); // พิมพ์แท็กสิ้นสุด} การลงทะเบียนโมฆะสาธารณะ (เธรด t) {ซิงโครไนซ์ (RunningThreads) {runningThreads.add (t); }} โมฆะสาธารณะ unregist (เธรด t) {ซิงโครไนซ์ (RunningThreads) {ซิงโครไนซ์ (RunningThreads) {RunningThreads.Remove (t); }} บูลีนสแตติกสาธารณะ hasthreadrunning () {return (runningthreads.size ()> 0); // โดยการตัดสินว่า RunningThreads ว่างเปล่าคุณสามารถรู้ได้ว่ายังมีเธรดที่ยังไม่ได้ดำเนินการ}}}}}}}}}}}}}}}}}} รหัสในเธรดหลัก:
Long TSTART = System.currentTimeMillis (); System.out.println (thread.currentthread (). getName ()+"start"); // พิมพ์เครื่องหมายเริ่มต้นสำหรับ (int ii = 0; ii <threadnum; ii ++) {// เปิดเธรดเธรด t = ใหม่ importThread (); T.Start (); } ในขณะที่ (จริง) {// รอให้เธรดเด็กทั้งหมดดำเนินการเสร็จสิ้นถ้า (! importThread.hasthreadRunning ()) {break; } thread.sleep (500); } system.out.println (thread.currentthread (). getName () + "end."); // พิมพ์ tag end tned long = System.currentTimeMillis (); System.out.println ("เวลาทั้งหมด:" + (แนวโน้ม - tstart) + "ล้าน");ผลการพิมพ์คือ:
การเริ่มต้นหลัก
เธรด -1 เริ่มต้น ...
เธรด -5 เริ่ม ...
เธรด -0 เริ่ม ...
Thread-2 เริ่มต้น ...
Thread-3 เริ่ม ...
Thread-4 เริ่ม ...
ด้าย -5 สิ้นสุด
Thread-4 สิ้นสุด
ด้าย -2 สิ้นสุด
Thread-0 สิ้นสุด
Thread-3 สิ้นสุด
ด้าย -1 สิ้นสุด
จุดสิ้นสุดของหลัก
เวลาทั้งหมด: 20860 ล้าน
คุณจะเห็นว่าเธรดหลักจะเริ่มดำเนินการหลังจากที่เธรดลูกทั้งหมดถูกดำเนินการ
- -
วิธีการข้างต้นมีอันตรายที่ซ่อนอยู่: หากเธรด 1 เริ่มต้นและสิ้นสุดและเธรดอื่น ๆ ยังไม่ได้เริ่มต้นขนาดของ RunningThreads เป็น 0 เธรดหลักจะคิดว่าเธรดทั้งหมดได้ถูกดำเนินการ วิธีแก้ปัญหาคือการแทนที่ประเภทรายการ RunningThreads ด้วยตัวนับประเภทที่ไม่ง่ายและควรตั้งค่าตัวนับก่อนการสร้างเธรด
คลาส MyCountdown
คลาสสาธารณะ MyCountdown {จำนวน int ส่วนตัว; สาธารณะ myCountdown (จำนวน int) {this.count = count; } การนับถอยหลังเป็นโมฆะที่ซิงโครไนซ์สาธารณะ () {นับ-; } public synchronized boolean hasnext () {return (count> 0); } public int getCount () {นับคืน; } โมฆะสาธารณะ setCount (จำนวน int) {this.count = count; - คลาส importThread
ชั้นเรียนสาธารณะ ImportThread ขยายเธรด {ส่วนตัว mycountdown c; Public ImportThread (MyCountdown C) {this.c = c; } @Override โมฆะสาธารณะ run () {system.out.println (thread.currentthread (). getName () + "เริ่มต้น ... "); // พิมพ์เครื่องหมายเริ่มต้น // ทำบางสิ่งบางอย่าง c.countdown (); สิ้นสุดเครื่องหมาย}} ในเธรดหลัก
System.out.println (thread.currentthread (). getName ()+"start"); // พิมพ์แท็กเริ่มต้น mycountdown c = ใหม่ mycountdown (threadnum); // เริ่มต้นนับถอยหลังสำหรับ (int ii = 0; ii <threadnum; ii ++) {// เปิดเธรด T.Start (); } ในขณะที่ (จริง) {// กำลังรอให้ทุกเธรดลูกเพื่อดำเนินการ if (! c.hasnext ()) break; } system.out.println (thread.currentthread (). getName () + "end."); // พิมพ์เครื่องหมายสิ้นสุดผลการพิมพ์:
การเริ่มต้นหลัก
Thread-2 เริ่มต้น ...
เธรด -1 เริ่มต้น ...
เธรด -0 เริ่ม ...
Thread-3 เริ่ม ...
เธรด -5 เริ่ม ...
Thread-4 เริ่ม ...
ด้าย -5 สิ้นสุด อีก 5 เธรด
ด้าย -1 สิ้นสุด มีอีก 4 เธรด
Thread-4 สิ้นสุด มีอีก 3 เธรด
ด้าย -2 สิ้นสุด อีก 2 เธรด
Thread-3 สิ้นสุด 1 เธรดยังคงอยู่ที่นั่น
Thread-0 สิ้นสุด เหลืออีก 0 เธรด
จุดสิ้นสุดของหลัก
วิธีที่ง่ายกว่า: ใช้ java.util.concurrent.countdownlatch แทน mycountdown ใช้วิธีรอ () แทนในขณะที่ (จริง) {... }
คลาส importThread
ชั้นเรียนสาธารณะ ImportThread ขยายเธรด {Private Countdownlatch ThreadsSignal; Public ImportThread (countdownlatch threadsSignal) {this.threadsSignal = threadsSignal; } @Override โมฆะสาธารณะเรียกใช้ () {system.out.println (thread.currentthread (). getName () + "เริ่ม ... "); // ทำบางสิ่งบางอย่าง threadssignal.countdown (); // ตัวนับจะลดลง 1 ในตอนท้ายของระบบเธรด system.out.println (thread.currentthread (). getName () + "จบนอกจากนี้ยังมี" + threadsSignal.getCount () + "เธรด"); - ในเธรดหลัก
countdownlatch threadsignal = new countdownlatch (threadnum); // เริ่มต้นนับถอยหลังสำหรับ (int ii = 0; ii <threadnum; ii ++) {// เปิดเธรดสุดท้ายตัววน เธรด t = importThread ใหม่ (ITT, SQL, ThreadSignal); T.Start (); } threadsignal.await (); // รอให้เธรดเด็กทั้งหมดเสร็จสิ้นระบบการดำเนินการที่สมบูรณ์ผลการพิมพ์:
การเริ่มต้นหลัก
เธรด -1 เริ่มต้น ...
เธรด -0 เริ่ม ...
Thread-2 เริ่มต้น ...
Thread-3 เริ่ม ...
Thread-4 เริ่ม ...
เธรด -5 เริ่ม ...
Thread-0 สิ้นสุด อีก 5 เธรด
ด้าย -1 สิ้นสุด มีอีก 4 เธรด
Thread-4 สิ้นสุด มีอีก 3 เธรด
ด้าย -2 สิ้นสุด อีก 2 เธรด
ด้าย -5 สิ้นสุด 1 เธรดยังคงอยู่ที่นั่น
Thread-3 สิ้นสุด เหลืออีก 0 เธรด
จุดสิ้นสุดของหลัก
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น