Java multithreading allows the main thread to wait for all child threads to finish executing

  • 2020-05-16 07:02:59
  • OfStack

My friend asked me to help write a program to import data from a text document into the oracle database. Technically, there was no difficulty. The format of the document was fixed as long as the corresponding fields in the database were parsed.

One million records data volume is very big, so consider to use multithreading concurrent execution, problems encountered in the process of writing and, I want to statistics the total time consuming all the child process has been completed, in front of the child process created 1. Record the current time using System currentTimeMillis () at the end of the last 1 child process record the current time, two 1 minus the time for a total of unavailable, namely the code below


long tStart = System.currentTimeMillis(); 
System.out.println(Thread.currentThread().getName() + " start ");// Print start mark  
for (int ii = 0; ii < threadNum; ii++) {// open threadNum A thread  
Runnable r = new Runnable(){ 
@Override 
public void run(){ 
System.out.println(Thread.currentThread().getName() + " start "); 
// do 1 Some of the things ... ... 
System.out.println(Thread.currentThread().getName() + " The end of the ."); 
} 
} 
Thread t = new Thread(r); 
t.start(); 
} 
System.out.println(Thread.currentThread().getName() + " The end of the .");// End of print mark  
long tEnd = System.currentTimeMillis(); 
System.out.println(" Elapsed time :"+ (tEnd - tStart) + "millions"); 

The result is that the main thread prints the statement for the total time almost immediately after the for loop ends, because all the child threads execute concurrently and the main thread is running while they are running, which leads to the question of how the title of this article "let the main thread wait for all the child threads to finish executing". I tried adding t.join () after each child thread started, and the result was that all threads were executed sequentially, which lost the sense of concurrency, which was obviously not what I wanted.

It's been a long time since Google has found a solution. Hasn't anyone ever encountered this demand? Or is the question too simple? I had to figure it out on my own...

Finally, my solution is to customize 1 ImportThread class inherited from java.lang.Thread, overload run() method, and use 1 List property to save all the generated threads, so as to determine whether the List is empty, we will know whether there are any child threads that haven't finished executing. The code of the class is as follows:


public class ImportThread extends Thread { 
private static List<Thread> runningThreads = new ArrayList<Thread>(); 
public ImportThread() { 
} 
@Override 
public void run() { 
regist(this);// Register when the thread starts  
System.out.println(Thread.currentThread().getName() + " start ...");// Print start mark  
// do 1 Some of the things ... ... 
unRegist(this);// Unregister when the thread ends  
System.out.println(Thread.currentThread().getName() + " The end of the .");// End of print mark  
} 
public void regist(Thread t){ 
  synchronized(runningThreads){  
    runningThreads.add(t); 
  } 
} 
public void unRegist(Thread t){ 
  synchronized(runningThreads){  
    runningThreads.remove(t); 
  } 
} 
public static boolean hasThreadRunning() { 
return (runningThreads.size() > 0);// By judging runningThreads If it's empty, you know if there's a thread that hasn't finished executing  
} 
} 

Code in the main thread:


long tStart = System.currentTimeMillis(); 
System.out.println(Thread.currentThread().getName() + " start ");// Print start mark  
for (int ii = 0; ii < threadNum; ii++) {// open threadNum A thread  
Thread t = new ImportThread(); 
t.start(); 
} 
while(true){// Wait for all child threads to finish executing  
if(!ImportThread.hasThreadRunning()){ 
break; 
} 
Thread.sleep(500); 
} 
System.out.println(Thread.currentThread().getName() + " The end of the .");// End of print mark  
long tEnd = System.currentTimeMillis(); 
System.out.println(" Elapsed time :"+ (tEnd - tStart) + "millions"); 

The result is:

main began
Thread - 1 start...
Thread - 5 start...
Thread - 0...
Thread - 2 start...
Thread - 3 start...
Thread - 4 start...
End of Thread - 5.
End of Thread - 4.
Thread - 2 end.
End of Thread - 0.
End of Thread - 3.
End of Thread - 1.
main end.

Total time :20860millions

You can see that the main thread does not start executing until all the child threads have finished executing.

=================================================================================================

There is a catch to this approach: if thread 1 starts and ends, and runningThreads's size is 0 before other threads start, the main thread will assume that all threads have finished executing. The solution is to replace List type runningThreads with a counter of a non-simple type, and the counter should be set before the thread is created.

MyCountDown class


  public class MyCountDown { 
private int count; 
public MyCountDown(int count){ 
this.count = count; 
} 
public synchronized void countDown(){ 
count--; 
} 
public synchronized boolean hasNext(){ 
return (count > 0); 
} 
public int getCount() { 
return count; 
} 
public void setCount(int count) { 
this.count = count; 
} 
} 

ImportThread class


 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 ...");// Print start mark  
//Do something 
c.countDown();// The timer to reduce 1 
System.out.println(Thread.currentThread().getName() + " The end of the .  There are " + c.getCount() + "  A thread ");// End of print mark  
} 
} 

In the main thread


System.out.println(Thread.currentThread().getName() + " start ");// Print start mark  
MyCountDown c = new MyCountDown(threadNum);// Initialize the countDown 
for (int ii = 0; ii < threadNum; ii++) {// open threadNum A thread  
Thread t = new ImportThread(c); 
t.start(); 
} 
while(true){// Wait for all child threads to finish executing  
if(!c.hasNext()) break; 
} 
System.out.println(Thread.currentThread().getName() + " The end of the .");// End of print mark  

Print result:

main began
Thread - 2 start...
Thread - 1 start...
Thread - 0...
Thread - 3 start...
Thread - 5 start...
Thread - 4 start...
Thread-5 ends. There are five more threads
Thread-1 is over. There are four more threads
Thread-4 ends. There are 3 more threads
Thread-2 ends. There are two more threads
Thread-3 ends. There's one more thread
Thread-0 ends. There are also 0 threads
main end.

More simple method: use the java. util. concurrent. CountDownLatch MyCountDown instead, use await () method instead of while (true) {... }

ImportThread class


public class ImportThread extends Thread { 
private CountDownLatch threadsSignal; 
public ImportThread(CountDownLatch threadsSignal) { 
this.threadsSignal = threadsSignal; 
} 
@Override 
public void run() { 
System.out.println(Thread.currentThread().getName() + " start ..."); 
//Do somethings 
threadsSignal.countDown();// The counter is decrement when the thread ends 1 
System.out.println(Thread.currentThread().getName() + " The end of the .  There are " + threadsSignal.getCount() + "  A thread "); 
} 
} 

In the main thread


CountDownLatch threadSignal = new CountDownLatch(threadNum);// Initialize the countDown 
for (int ii = 0; ii < threadNum; ii++) {// open threadNum A thread  
final Iterator<String> itt = it.get(ii); 
Thread t = new ImportThread(itt,sql,threadSignal); 
t.start(); 
} 
threadSignal.await();// Wait for all child threads to finish executing  
System.out.println(Thread.currentThread().getName() + " The end of the .");// End of print mark  

Print result:

main began
Thread - 1 start...
Thread - 0...
Thread - 2 start...
Thread - 3 start...
Thread - 4 start...
Thread - 5 start...
Thread-0 ends. There are 5 more threads
Thread-1 is over. There are four more threads
Thread-4 ends. There are three more threads
Thread-2 ends. There are two more threads
Thread-5 ends. There's one more thread
Thread-3 ends. There are 0 threads left
main end.


Related articles: