Мой друг попросил меня помочь мне написать программу для импорта данных из текстового документа в базу данных Oracle. Это технически не сложно. Формат документа фиксирован. До тех пор, пока соответствующий анализ поля в базе данных достаточно, ключ заключается в производительности.
Объем данных большой и миллионы записей. Поэтому, учитывая, что вам необходимо использовать многопоточное одновременное выполнение, и вы сталкиваетесь с проблемами в процессе написания, я хочу подсчитать общее время, потраченное на все дочерние процессы после завершения выполнения. Запишите текущее время до создания первого дочернего процесса. Используйте System.currentTimeMillis () для записи текущего времени после завершения последнего дочернего процесса. Разница во времени, полученная дважды вычитанием, является общим временем. Код выглядит следующим образом
long tStart = System.currentTimeMiLlis (); System.out.println (thread.currentThread (). GetName () + "start"); // Распечатать марку для (int ii = 0; ii <threadnum; ii ++) {// Открыть потоки Runnable r = new Runnable () {@Override public run () {system.out.println (think.currentThread (). // что -то сделать ... ... System.out.println (Thread.currentThread (). GetName () + "end."); }} Поток t = новый поток (r); t.start (); } System.out.println (thread.currentThread (). GetName () + "end."); // Печать End Tag long tid = System.currentTimeMillis (); System.out.println («Общее время:» + (tend - tStart) + «миллионы»); Результатом является то, что операторы, используемые основным потоком для печати общего времени, выполняются практически в тот момент, когда заканчиваются цикла. Причина в том, что все детские потоки выполняются одновременно, и основной поток также работает при запуске, что поднимает вопрос: как «заставить основной поток ждать, пока все дочерние потоки выполнят». Я попытался добавить t.join () после запуска каждого дочернего потока, и результат заключается в том, что все потоки выполняются последовательно, что теряет смысл параллелизма, что, очевидно, не то, что я хочу.
Google давно не нашел решение онлайн. Никто никогда не сталкивался с такой потребностью? Или эта проблема слишком проста? Ву Най должен был думать о решении сам ...
Наконец, мое решение состоит в том, чтобы настроить наследники класса ImportThread от java.lang.thread, перегружать метод run () и использовать свойство списка для сохранения всех сгенерированных потоков. Таким образом, пока вы судите, является ли список пустым, вы будете знать, есть ли еще детские потоки, которые не были выполнены. Код класса выглядит следующим образом:
публичный класс ImportThread Extends Thread {Private Static List <Think> runningThreads = new ArrayList <thenk> (); public importThread () {} @Override public void run () {Registration (this); // Регистрация System.out.println (thread.currentThread (). getName () + "start ..."); // Печать маркера начала // делайте что -нибудь ... unregist (this); // unregister system.out.println (thread.currentthrentth "End."); // Распечатать The End Tag} public void Registration (Thread T) {synchronized (rongThreads) {runningThreads.add (t); }} public void uneRegist (Thread T) {Synchronized (runningThreads) {synchronized (rongThreads) {runningThreads.remove (t); }} public static boolean hasThreadrunning () {return (ronghreads.size ()> 0); // Оценив, пуста ли hundreads, вы можете знать, есть ли еще потоки, которые не были выполнены}} Код в главной ветке:
long tStart = System.currentTimeMiLlis (); System.out.println (Thread.currentThread (). GetName ()+"start"); // Распечатать марку начала для (int ii = 0; ii <threadnum; ii ++) {// Открыть потоковые потоки t = new importThread (); t.start (); } while (true) {// ждать, пока все детские потоки завершит выполнение if (! importThread.HaSTHreadRunning ()) {Break; } Thread.sleep (500); } System.out.println (thread.currentThread (). GetName () + "end."); // Печать End Tag long tid = System.currentTimeMillis (); System.out.println («Общее время:» + (tend - tStart) + «миллионы»);Результат печати:
Главный старт
Thread-1 начинается ...
Thread-5 начинается ...
Thread-0 начинается ...
Thread-2 начинается ...
Thread-3 начинается ...
Thread-4 начинается ...
Поток-5 заканчивается.
Поток-4 заканчивается.
Поток 2 заканчивается.
Поток-0 заканчивается.
Поток-3 заканчивается.
Поток 1 заканчивается.
Конец главного.
Общее время: 20860 млн
Вы можете видеть, что основной поток только начинает выполнение после выполнения всех детских потоков.
========================================================================== ===========================================================================
Приведенный выше метод содержит скрытую опасность: если поток 1 запускается и заканчивается, а другие потоки еще не начались, размер runningthreads также равен 0, основной поток будет думать, что все потоки были выполнены. Решение состоит в том, чтобы заменить тип списка runningThreads на счетчик непреодолимого типа, а значение счетчика должно быть установлено перед созданием потока.
MyCountDown Class
открытый класс myCountdown {private int count; public myCountdown (int count) {this.count = count; } public void countdown () {count--; } public synchronized boolean hasnext () {return (count> 0); } public int getCount () {return count; } public void setCount (int count) {this.count = count; }} Импортный класс
Public Class ImportThread Extends Thread {Private MyCountDown C; public ImportThread (MyCountDown C) {this.c = c; } @Override public void run () {system.out.println (thread.currentThread (). GetName () + "start ..."); // распечатать маркер запуска // сделать что -нибудь c.countdown (); // Timer Minus 1 System.out.println (thread.currentThread () printems () end и " + c.getcount ()") ")") "). Конец Марка}} В главной ветке
System.out.println (Think.currentThread (). GetName ()+"start"); // Распечатать tag Tag MyCountDown c = новый myCountdown (threadnum); // Инициализировать обратный отсчет для (int ii = 0; ii <threadnum; ii ++) {// Откройте потоки Teads Tecktdow t.start (); } while (true) {// ждать, пока все дочерние потоки выполнят if (! c.hasnext ()) break; } System.out.println (Thread.currentThread (). GetName () + "End."); // Распечатать конечную маркуРезультат печати:
Главный старт
Thread-2 начинается ...
Thread-1 начинается ...
Thread-0 начинается ...
Thread-3 начинается ...
Thread-5 начинается ...
Thread-4 начинается ...
Поток-5 заканчивается. Еще 5 потоков
Поток 1 заканчивается. Есть еще 4 потока
Поток-4 заканчивается. Есть еще 3 потока
Поток 2 заканчивается. Еще 2 потока
Поток-3 заканчивается. 1 теме все еще там
Поток-0 заканчивается. Осталось 0 потоков
Конец главного.
Проще говоря: используйте java.util.concurrent.countdownlatch вместо mycountdown, используйте метод wait () вместо (true) {...}
Импортный класс
публичный класс ImportThread Extends Thread {Private CountDownLatch ThreadsSignal; public importThread (countdownlatch ThreadsSignal) {this.ThreadsSignal = ThreadsSignal; } @Override public void run () {System.out.println (thread.currentThread (). GetName () + "start ..."); // Сделать что -то ThreadsIgnal.countdown (); // счетчик уменьшается на 1 в конце системы потока. }} В главной ветке
Countdownlatch threadsignal = new CountdownLatch (ThreadNum); // Инициализировать обратный отсчет для (int ii = 0; ii <threadnum; ii ++) {// Открыть потоки итератор <string> itt = it.get (ii); Поток t = new ImportThread (ITT, SQL, ThreadSignal); t.start (); } threadsignal.await (); // ожидание всех дочерних потоков завершить систему выполнения.Результат печати:
Главный старт
Thread-1 начинается ...
Thread-0 начинается ...
Thread-2 начинается ...
Thread-3 начинается ...
Thread-4 начинается ...
Thread-5 начинается ...
Поток-0 заканчивается. Еще 5 потоков
Поток 1 заканчивается. Есть еще 4 потока
Поток-4 заканчивается. Есть еще 3 потока
Поток 2 заканчивается. Еще 2 потока
Поток-5 заканчивается. 1 теме все еще там
Поток-3 заканчивается. Осталось 0 потоков
Конец главного.
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.