Java 다중 스레드 - 모든 하위 스레드가 실행될 때까지 기본 스레드를 기다립니다.

친구는 나에게 프로그램을 써서 텍스트 문서에서oracle 데이터베이스로 가져오라고 했다. 기술적으로 어려움이 없고 문서의 형식은 모두 고정되어 있으며 데이터베이스에 대응하는 필드 해석만 하면 된다. 관건은 성능에 있다.
데이터량이 매우 많은 백만 개의 기록을 가지고 있기 때문에 다중 루틴으로 병행하여 실행해야 한다는 것을 고려하여 쓰는 과정에서 또 문제가 발생했습니다. 저는 모든 하위 프로세스가 실행되는 데 총 소모된 시간을 통계하고 싶습니다. 첫 번째 하위 프로세스가 생성되기 전에 현재 시간을 시스템으로 기록하고 싶습니다.currentTimeMillis () 는 마지막 하위 프로세스가 끝난 후 현재 시간을 기록합니다. 두 번 한 번 감량한 시간차는 모두 사용됩니다. 코드는 다음과 같습니다.

long tStart = System.currentTimeMillis(); 
System.out.println(Thread.currentThread().getName() + " ");//  
for (int ii = 0; ii < threadNum; ii++) {// threadNum  
Runnable r = new Runnable(){ 
@Override 
public void run(){ 
System.out.println(Thread.currentThread().getName() + " "); 
// ... ... 
System.out.println(Thread.currentThread().getName() + " ."); 
} 
} 
Thread t = new Thread(r); 
t.start(); 
} 
System.out.println(Thread.currentThread().getName() + " .");//  
long tEnd = System.currentTimeMillis(); 
System.out.println(" :"+ (tEnd - tStart) + "millions"); 
결과는 거의 for순환이 끝나는 순간에 주 스레드 인쇄가 모두 사용될 때의 문장을 실행했다. 왜냐하면 모든 하위 스레드가 병렬적으로 실행되고 그들이 실행할 때 주 스레드도 실행되기 때문이다. 이것은 본고의 제목이 어떻게'모든 하위 스레드가 실행되기를 기다리게 하는가'라는 문제를 불러일으켰다.모든 하위 스레드가 시작된 후에 t.join () 를 추가해 보았는데, 결과는 모든 스레드가 순서대로 실행되었고, 이것은 병발의 의미를 잃었다. 분명히 내가 원하는 것이 아니다. 
인터넷에서 Google이 오랫동안 해결 방안을 찾지 못했는데 이런 수요를 만난 사람이 없나요?아니면 이 문제가 너무 간단한가요?어쩔 수 없이 스스로 방법을 강구해야 하는데.. 
마지막으로 나의 해결 방법은 ImportThread 클래스를 자바에서 계승하는 것을 사용자 정의하는 것이다.lang.Thread,run()을 다시 불러오는 방법,List 속성으로 생성된 모든 라인을 저장합니다. 이 List가 비어 있는지 판단하면 하위 라인이 실행되지 않았는지 알 수 있습니다. 클래스 코드는 다음과 같습니다.

public class ImportThread extends Thread { 
private static List<Thread> runningThreads = new ArrayList<Thread>(); 
public ImportThread() { 
} 
@Override 
public void run() { 
regist(this);//  
System.out.println(Thread.currentThread().getName() + " ...");//  
// ... ... 
unRegist(this);//  
System.out.println(Thread.currentThread().getName() + " .");//  
} 
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);// runningThreads  
} 
} 
주 스레드의 코드:

long tStart = System.currentTimeMillis(); 
System.out.println(Thread.currentThread().getName() + " ");//  
for (int ii = 0; ii < threadNum; ii++) {// threadNum  
Thread t = new ImportThread(); 
t.start(); 
} 
while(true){//  
if(!ImportThread.hasThreadRunning()){ 
break; 
} 
Thread.sleep(500); 
} 
System.out.println(Thread.currentThread().getName() + " .");//  
long tEnd = System.currentTimeMillis(); 
System.out.println(" :"+ (tEnd - tStart) + "millions"); 
인쇄 결과는 다음과 같습니다.
main 시작
쓰레드. - 1부터... 
쓰레드. - 5 부터... 
쓰레드 - 0부터... 
쓰레드. - 2 시작... 
쓰레드. - 3 부터... 
쓰레드 - 4 부터... 
Thread-5 종료. 
Thread-4 끝. 
Thread-2 끝. 
Thread-0 끝. 
Thread-3 종료. 
Thread-1 끝. 
main 끝.          
총 사용시: 20860millions
main 스레드는 모든 하위 스레드가 실행된 후에야 실행되는 것을 볼 수 있습니다. 
================================================================================================= 
위의 방법에는 위험이 하나 있다. 만약에 스레드 1이 시작되고 끝났고 다른 스레드가 시작되지 않았다면 이 때runningThreads의size도 0이고 메인 스레드는 모든 스레드가 실행되었다고 생각할 것이다.해결 방법은 목록형의runningThreads를 간단하지 않은 유형의 계수기로 대체하고, 라인이 만들어지기 전에 계수기의 값을 설정해야 한다. 
MyCountDown 클래스
 

  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 클래스

 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() + " ...");//  
//Do something 
c.countDown();// 1 
System.out.println(Thread.currentThread().getName() + " .  " + c.getCount() + "  ");//  
} 
} 
주 스레드 중

System.out.println(Thread.currentThread().getName() + " ");//  
MyCountDown c = new MyCountDown(threadNum);// countDown 
for (int ii = 0; ii < threadNum; ii++) {// threadNum  
Thread t = new ImportThread(c); 
t.start(); 
} 
while(true){//  
if(!c.hasNext()) break; 
} 
System.out.println(Thread.currentThread().getName() + " .");//  
인쇄 결과:
main 시작
쓰레드. - 2 시작... 
쓰레드. - 1부터... 
쓰레드 - 0부터... 
쓰레드. - 3 부터... 
쓰레드. - 5 부터... 
쓰레드 - 4 부터... 
Thread-5 종료.아직 다섯 개의 노선이 있다
Thread-1 끝.아직 4 개의 노선이 있다
Thread-4 끝.아직 세 개의 노선이 있다
Thread-2 끝.아직 두 개의 노선이 있다
Thread-3 종료.아직 1개 남았어요.
Thread-0 끝.아직 0 개의 루트가 있다
main 끝. 
더 간단한 방법:java를 사용합니다.util.concurrent.MyCountDown 대신 CountDownLatch, while (true) 대신 await () 방법으로 {...}
ImportThread 클래스

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() + " ..."); 
//Do somethings 
threadsSignal.countDown();// 1 
System.out.println(Thread.currentThread().getName() + " .  " + threadsSignal.getCount() + "  "); 
} 
} 
주 스레드 중

CountDownLatch threadSignal = new CountDownLatch(threadNum);// countDown 
for (int ii = 0; ii < threadNum; ii++) {// threadNum  
final Iterator<String> itt = it.get(ii); 
Thread t = new ImportThread(itt,sql,threadSignal); 
t.start(); 
} 
threadSignal.await();//  
System.out.println(Thread.currentThread().getName() + " .");//  
인쇄 결과:
main 시작
쓰레드. - 1부터... 
쓰레드 - 0부터... 
쓰레드. - 2 시작... 
쓰레드. - 3 부터... 
쓰레드 - 4 부터... 
쓰레드. - 5 부터... 
Thread-0 끝.아직 다섯 개의 노선이 있다
Thread-1 끝.아직 4 개의 노선이 있다
Thread-4 끝.아직 세 개의 노선이 있다
Thread-2 끝.아직 두 개의 노선이 있다
Thread-5 종료.아직 1개 남았어요.
Thread-3 종료.아직 0 개의 루트가 있다
main 끝.
이상은 본문의 전체 내용입니다. 여러분의 학습에 도움이 되고 저희를 많이 응원해 주십시오.

좋은 웹페이지 즐겨찾기