Teman saya meminta saya untuk membantu saya menulis program untuk mengimpor data dari dokumen teks ke dalam database Oracle. Secara teknis tidak sulit. Format dokumen diperbaiki. Selama analisis bidang yang sesuai dalam database sudah cukup, kuncinya terletak pada kinerja.
Volume data besar dan jutaan catatan. Oleh karena itu, mengingat bahwa Anda perlu menggunakan eksekusi bersamaan multi-thread, dan Anda menghadapi masalah selama proses penulisan, saya ingin menghitung total waktu yang dihabiskan untuk semua proses anak setelah eksekusi selesai. Catat waktu saat ini sebelum proses anak pertama dibuat. Gunakan System.CurrentTimemillis () untuk mencatat waktu saat ini setelah proses anak terakhir selesai. Perbedaan waktu yang diperoleh dengan pengurangan dua kali adalah total waktu. Kodenya adalah sebagai berikut
long tStart = system.currentTimemillis (); System.out.println(Thread.currentThread().getName() + "Start");//Print the start mark for (int ii = 0; ii < threadNum; ii++) {//Open threads Runnable r = new Runnable(){ @Override public void run(){ System.out.println(Thread.currentThread().getName() + "Start"); // lakukan sesuatu ... ... System.out.println (thread.currentThread (). GetName () + "end."); }} Utas t = utas baru (r); t.start (); } System.out.println (thread.currentThread (). GetName () + "end."); // cetak tag akhir long tend = system.currentTimeMillis (); System.out.println ("Total waktu:" + (cenderung - tstart) + "jutaan"); Hasilnya adalah bahwa pernyataan yang digunakan oleh utas utama untuk mencetak total waktu dieksekusi hampir saat loop berakhir. Alasannya adalah bahwa semua utas anak dieksekusi secara bersamaan, dan utas utama juga berjalan ketika mereka berjalan, yang menimbulkan pertanyaan: bagaimana "membuat utas utama menunggu semua utas anak dieksekusi." Saya mencoba menambahkan t.join () setelah setiap utas anak dimulai, dan hasilnya adalah bahwa semua utas dieksekusi secara berurutan, yang kehilangan makna konkurensi, yang jelas bukan yang saya inginkan.
Google sudah lama tidak menemukan solusi online. Tidak ada yang pernah menghadapi kebutuhan seperti itu? Atau apakah masalah ini terlalu sederhana? Wu Nai harus memikirkan solusi sendiri ...
Akhirnya, solusi saya adalah menyesuaikan kelas importThread yang diwariskan dari java.lang.thread, kelebihan metode run (), dan menggunakan properti daftar untuk menyimpan semua utas yang dihasilkan. Dengan cara ini, selama Anda menilai apakah daftarnya kosong, Anda akan tahu apakah masih ada utas anak yang belum dieksekusi. Kode kelas adalah sebagai berikut:
Public Class ImportThread Extends Thread {Private Static List <Hread> runningThreads = ArrayList baru <tread> (); Public ImportThread () {} @Override public void run () {Registrasi (this); // register system.out.println (thread.currentThread (). getName () + "start ..."); // cetak marker // lakukan sesuatu ... tidak terdaftar (this); // unregister system.out.out.prinTlllln (crintl.currad (ini). "end."); // cetak tag akhir} Registrasi public void (thread t) {disinkronkan (runningThreads) {runningthreads.add (t); }} public void unregist (thread t) {disinkronkan (runningThreads) {disinkronkan (runningThreads) {runningthreads.remove (t); }} public static boolean hasthreadrunning () {return (runningthreads.size ()> 0); // dengan menilai apakah runnthreads kosong, Anda dapat tahu apakah masih ada utas yang belum dieksekusi}} Kode di utas utama:
long tStart = system.currentTimemillis (); System.out.println (thread.currentThread (). GetName ()+"start"); // cetak tanda start untuk (int ii = 0; ii <threadnum; ii ++) {// buka utas utas t = importThread baru (); t.start (); } while (true) {// menunggu semua utas anak untuk menyelesaikan eksekusi jika (! importThread.hasThreadRunning ()) {break; } Thread.sleep (500); } System.out.println (thread.currentThread (). GetName () + "end."); // cetak tag akhir long tend = system.currentTimeMillis (); System.out.println ("Total waktu:" + (cenderung - tstart) + "jutaan");Hasil cetak adalah:
Awal utama
Thread-1 dimulai ...
Thread-5 dimulai ...
Thread-0 dimulai ...
Thread-2 dimulai ...
Thread-3 dimulai ...
Thread-4 dimulai ...
Thread-5 berakhir.
Thread-4 berakhir.
Thread-2 berakhir.
Thread-0 berakhir.
Thread-3 berakhir.
Thread-1 berakhir.
Akhir utama.
Total waktu: 20860 juta
Anda dapat melihat bahwa utas utama hanya memulai eksekusi setelah semua utas anak dieksekusi.
======================================================================= ========================================================================
Metode di atas memiliki bahaya tersembunyi: Jika utas 1 dimulai dan berakhir, dan utas lainnya belum dimulai, ukuran runningthreads juga 0, utas utama akan berpikir bahwa semua utas telah dieksekusi. Solusinya adalah mengganti jenis daftar RunningThreads dengan penghitung tipe non-sederhana, dan nilai penghitung harus ditetapkan sebelum pembuatan utas.
Kelas MyCountdown
kelas publik mycountdown {private int count; public mycountdown (int count) {this.count = count; } public disinkronkan void countDown () {count--; } public yang disinkronkan boolean hasnext () {return (count> 0); } public int getCount () {return count; } public void setCount (int count) {this.count = count; }} Kelas importThread
Public Class ImportThread memperluas Thread {Private MyCountdown C; importThread publik (MyCountdown c) {this.c = c; } @Override public void run () {System.out.println (thread.currentThread (). GetName () + "start ..."); // cetak penanda start // lakukan sesuatu c.countdown (); // timer minus 1 System.out.println (thread.currentThread (). GetName () ") ()") () "endtln (thread.currentThread (). akhir tanda}} Di utas utama
System.out.println (thread.currentThread (). GetName ()+"start"); // cetak tag start mycountdown c = mycountdown baru (threadnum);//inisialisasi hitung mundur untuk (int ii = 0; ii <threadnum; ii ++) {// buka thread thread t = impor baru (c); t.start (); } while (true) {// menunggu semua utas anak untuk mengeksekusi if (! c.hasnext ()) break; } System.out.println (thread.currentThread (). GetName () + "end."); // cetak tanda akhirHasil Cetak:
Awal utama
Thread-2 dimulai ...
Thread-1 dimulai ...
Thread-0 dimulai ...
Thread-3 dimulai ...
Thread-5 dimulai ...
Thread-4 dimulai ...
Thread-5 berakhir. 5 utas lagi
Thread-1 berakhir. Ada 4 utas lagi
Thread-4 berakhir. Ada 3 utas lagi
Thread-2 berakhir. 2 utas lagi
Thread-3 berakhir. 1 Thread masih ada
Thread-0 berakhir. Ada 0 utas tersisa
Akhir utama.
Cara yang lebih mudah: Gunakan java.util.concurrent.countdownlatch bukannya MyCountdown, gunakan metode waait () alih -alih while (true) {...}
Kelas importThread
Public Class ImportThread memperluas thread {private CountdownLatch ThreadsSignal; Public ImportThread (CountdownLatch ThreadsSignal) {this.threadssignal = threadssignal; } @Override public void run () {System.out.println (thread.currentThread (). GetName () + "start ..."); // Lakukan sesuatu threadssignal.countdown (); // penghitung dikurangi dengan 1 di akhir thread system.out.println (thread.currentThread (). GetName () + "end. Ada juga" + threadssignal.getCount () + "Threads"); }} Di utas utama
CountDownlatch threadSignal = countdownlatch baru (threadnum); // inisialisasi hitungan mundur untuk (int ii = 0; ii <threadnum; ii ++) {// buka thread final iterator <string> itt = it.get (ii); Thread t = new importthread (itt, sql, threadSignal); t.start (); } threadSignal.Await (); // menunggu semua utas anak untuk menyelesaikan sistem eksekusi.out.println (thread.currentThread (). getName () + "end."); // cetak tanda akhirHasil Cetak:
Awal utama
Thread-1 dimulai ...
Thread-0 dimulai ...
Thread-2 dimulai ...
Thread-3 dimulai ...
Thread-4 dimulai ...
Thread-5 dimulai ...
Thread-0 berakhir. 5 utas lagi
Thread-1 berakhir. Ada 4 utas lagi
Thread-4 berakhir. Ada 3 utas lagi
Thread-2 berakhir. 2 utas lagi
Thread-5 berakhir. 1 Thread masih ada
Thread-3 berakhir. Ada 0 utas tersisa
Akhir utama.
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.