Mi amigo me pidió que me ayudara a escribir un programa para importar datos de un documento de texto en una base de datos Oracle. No es técnicamente difícil. El formato del documento se fija. Mientras el análisis de campo correspondiente en la base de datos sea suficiente, la clave radica en el rendimiento.
El volumen de datos es grande y millones de registros. Por lo tanto, teniendo en cuenta que necesita usar la ejecución concurrente de múltiples subprocesos y encontrar problemas durante el proceso de escritura, quiero contar el tiempo total dedicado a todos los procesos infantiles después de completar la ejecución. Registre la hora actual antes de que se cree el primer proceso infantil. Use System.CurrentTimemillis () para registrar la hora actual después de que se complete el último proceso infantil. La diferencia de tiempo obtenida por subtracción dos veces es el tiempo total. El código es el siguiente
long tstart = System.CurrentTimemillis (); System.out.println (thread.currentThread (). GetName () + "inicio"); // Imprima la marca de inicio para (int ii = 0; ii <threadnum; ii ++) {// abre hilos runnables r = new runnable () {@Override public void run () {system.println (hilo.currentTthread (). // Haz algo ... ... System.out.println (Thread.CurrentThread (). GetName () + "End."); }} Hilo t = nuevo hilo (r); t.Start (); } System.out.println (thread.currentThread (). GetName () + "end.");/Print end etiqueta long tend = system.currentTimemillis (); System.out.println ("Total Time:" + (tend - tStart) + "millones"); El resultado es que las declaraciones utilizadas por el hilo principal para imprimir el tiempo total se ejecutan casi en el momento en que termina el bucle. La razón es que todos los hilos infantiles se ejecutan simultáneamente, y el hilo principal también se está ejecutando cuando se ejecutan, lo que plantea una pregunta: cómo "hacer que el hilo principal espere a que se ejecuten todos los hilos de los niños". Intenté agregar t.Join () después de que se inicia cada hilo infantil, y el resultado es que todos los hilos se ejecutan secuencialmente, lo que pierde el significado de concurrencia, que obviamente no es lo que quiero.
Google no ha encontrado una solución en línea durante mucho tiempo. ¿Nadie se ha encontrado con tal necesidad? ¿O este problema es demasiado simple? Wu Nai tuvo que pensar en una solución él mismo ...
Finalmente, mi solución es personalizar una clase de importación Hereda de java.lang.thread, sobrecargar el método run () y usar una propiedad de lista para guardar todos los subprocesos generados. De esta manera, mientras juzgue si la lista está vacía, sabrá si todavía hay hilos infantiles que no se han ejecutado. El código de clase es el siguiente:
Public Class ImportThread extiende el hilo {Lista estática privada <Shifre> RunningThreads = new ArrayList <Shifre> (); public import thread () {} @Override public void run () {Registration (this); // Register System.out.println (Thread.CurrentThread (). "End."); // Imprima la etiqueta final} registro público vacío (hilo t) {sincronizado (runnthreads) {runningThreads.Add (t); }} public void no regist (hilo t) {sincronizado (runnthreads) {sincronizado (runnthreads) {runnthreads.remove (t); }} public static static Boolean HasthreadRunning () {return (Runnthreads.size ()> 0); // Juzgando si RunningThreads está vacío, puede saber si todavía hay hilos que no se han ejecutado}} Código en el hilo principal:
long tstart = System.CurrentTimemillis (); System.out.println (thread.currentThread (). GetName ()+"inicio"); // imprima la marca de inicio para (int ii = 0; ii <threadnum; ii ++) {// abrir hilos hilo t = new importthread (); t.Start (); } while (true) {// Esperando que todos los hilos infantiles completen la ejecución if (! importthread.hasthreadrunning ()) {break; } Thread.sleep (500); } System.out.println (thread.currentThread (). GetName () + "end.");/Print end etiqueta long tend = system.currentTimemillis (); System.out.println ("Total Time:" + (tend - tStart) + "millones");El resultado de la impresión es:
Comienzo principal
Hilo-1 comienza ...
Hilo-5 comienza ...
Hilo-0 comienza ...
Hilo-2 comienza ...
Hilo-3 comienza ...
Hilo-4 comienza ...
Tema-5 extremos.
Tema-4 termina.
Tema-2 termina.
Tema-0 termina.
Tema-3 termina.
El hilo-1 termina.
El final de Main.
Tiempo total: 20860 millones
Puede ver que el hilo principal solo comienza la ejecución después de que se ejecutan todos los hilos de niños.
========================================================================================================= ==========================================================================================================
El método anterior tiene un peligro oculto: si el hilo 1 comienza y termina, y otros hilos aún no han comenzado, el tamaño de Runnthreads también es 0, el hilo principal pensará que todos los hilos se han ejecutado. La solución es reemplazar el tipo de lista RunningThreads con un contador de tipo no simple, y el valor del contador debe establecerse antes de la creación de subprocesos.
Clase de MyCountdown
clase pública myCountDown {private int count; public myCountDown (int count) {this.count = count; } public sincronizado void Countdown () {Count--; } public sincronizado Boolean HasNext () {return (Count> 0); } public int getCount () {return Count; } public void setCount (int count) {this.count = count; }} Clase de importación
Public Class ImportThread extiende Thread {Private MyCountDown C; Public ImportThread (MyCountDown C) {this.c = c; } @Override public void run () {System.out.println (Thread.CurrentThread (). GetName () + "Start ..."); // Imprima el marcador de inicio // hacer algo C.CountDown (); // Timer Minus 1 System.out.Println (Thread.CurrentThead (). GetName () + "end. final de la marca}} En el hilo principal
System.out.println (thread.currentThread (). GetName ()+"inicio"); // Imprima la etiqueta de inicio myCountDown c = new MyCountDown (ThreadNum); // Inicializar Countdown para (int II = 0; II <ThreadNum; II ++) {// Hilos abiertos TREST T = New ImportThread (C); t.Start (); } while (true) {// esperando que todos los hilos de niños se ejecuten if (! c.hasnext ()) break; } System.out.println (thread.currentThread (). GetName () + "end"); // Imprima la marca finalResultado de impresión:
Comienzo principal
Hilo-2 comienza ...
Hilo-1 comienza ...
Hilo-0 comienza ...
Hilo-3 comienza ...
Hilo-5 comienza ...
Hilo-4 comienza ...
Tema-5 extremos. 5 hilos más
El hilo-1 termina. Hay 4 hilos más
Tema-4 termina. Hay 3 hilos más
Tema-2 termina. 2 hilos más
Tema-3 termina. 1 hilo sigue ahí
Tema-0 termina. Quedan 0 hilos
El final de Main.
Manera más fácil: use java.util.concurrent.countdownlatch en lugar de myCountDown, use el método await () en lugar de while (true) {...}
Clase de importación
Public Class ImportThread extiende Thread {private CountdownLatch ThreadsSignal; public importthread (CountDownLatch ThreadsSignal) {this.threadssignal = ThreadsSignal; } @Override public void run () {System.out.println (Thread.CurrentThread (). GetName () + "Inicio ..."); // hacer algo ThreadsSignal.CountDown (); // El contador se reduce en 1 al final del hilo System.out.println (Thread.CurrentThread (). GetName () + "End. También hay" + ThreadsSignal.getCount () + "Threads"); }} En el hilo principal
CountDownLatch ThreadSignal = new CountDownLatch (ThreadNum); // Inicializar Countdown para (int ii = 0; ii <threadnum; ii ++) {// abrir hilos finales iterator <tring> itt = it.get (ii); Thread t = new ImportThread (ITT, SQL, ThreadSignal); t.Start (); } ThreadSignal.Await (); // Esperando que todos los hilos infantiles completen el sistema de ejecución.Resultado de impresión:
Comienzo principal
Hilo-1 comienza ...
Hilo-0 comienza ...
Hilo-2 comienza ...
Hilo-3 comienza ...
Hilo-4 comienza ...
Hilo-5 comienza ...
Tema-0 termina. 5 hilos más
El hilo-1 termina. Hay 4 hilos más
Tema-4 termina. Hay 3 hilos más
Tema-2 termina. 2 hilos más
Tema-5 extremos. 1 hilo sigue ahí
Tema-3 termina. Quedan 0 hilos
El final de Main.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.