J2EE学习笔记
我们的失落……
posts - 13,comments - 1,trackbacks - 0

原文出处:http://blog.chenlb.com/2008/11/join-or-countdownlatch-make-main-thread-wait-all-sub-thread.html

在编写多线程的工作中,有个常见的问题:主线程(main) 启动好几个子线程(task)来完成并发任务,主线程要等待所有的子线程完成之后才继续执行main的其它任务。
默认主线程退出时其它子线程不会停,如果想让main退出时其它子线程终止,可以用subThread.setDaemon(true) 设置子线程为“守护线程”。但现在要的是主线程等待所有子线程完成后,还要执行其它操作(比如:结果合并)。记得可以用join()方法来等待所有子线程完成后,才继续执行。如果不用join(),main线程与子线程是并发的,要稍加处理使main线程暂停。简单点用Thread.sleep(long millis) 了,当然用“等待-通知”机制也可以。
下面是用join的实现main等待所有子线程完成了,示例代码:WaitAllSubThread.java。

package com.chenlb;   
  
import java.util.Random;   
  
/**  
 * 
@author chenlb 2008-11-1 下午11:32:43  
 
*/
  
public class WaitAllSubThread {   
  
    
/*int liveThreadNum;//记录运行的子线程数  
    
*/
  
    
int n;  //工作线程数   
  
    
public WaitAllSubThread(int n) {   
        
this.n = n;   
    }
   
  
    
class Worker implements Runnable {   
  
        String name;   
        
int sleep;   
  
        
public Worker(String name, int sleep) {   
            
this.name = name;   
            
this.sleep = sleep;   
        }
   
  
        
public void run() {   
            
/*upLive(); //计算此线程已经工作.  
            
*/
  
            System.out.println(name
+", start to work.");   
            
try {   
                Thread.sleep(sleep);    
//虚拟工作. 10s 随机时间   
            }
 catch (InterruptedException e) {   
                System.out.println(name
+" interrupted.");   
            }
   
            System.out.println(name
+", end to work ["+sleep+"] sleep.");   
            
/*downLive();   //此线程工作完成  
            
*/
  
        }
   
    }
   
/*  //记录线程数的同步方法.  
    private synchronized void downLive() {  
        liveThreadNum--;  
    }  
 
    private synchronized void upLive() {  
        liveThreadNum++;  
    }  
 
    private synchronized boolean isLive() {  
        return liveThreadNum > 0;  
    }
*/
  
  
    
public void run() {   
        System.out.println(
"-------------main run start-------------");   
        
int sleepSaid = 10 * 1000;  //每个工作线程虚拟工作最大时间   
        Random rm = new Random();   
        
for(int i=0; i<ths.length; i++{   
            ths[i] 
= new Thread(new MyTask(rm.nextInt(sleep)+1));   
  
            ths[i].start();   
        }
   
  
        
for(Thread th : ths) {   
            
try {   
                th.join();
//join方式   
            }
 catch (InterruptedException e) {   
                
// TODO Auto-generated catch block   
                e.printStackTrace();   
            }
   
        }
   
        
/*//等待所有工作线程完成.  
        while(isLive()) {  
            try {  
                Thread.sleep(1000); //每隔1s查看下是否所有线程完成.  
            } catch (InterruptedException e) {  
                System.out.println("main thread sleep interrupted.");  
            }  
        }
*/
  
        System.out.println(
"---------------main run end--------------");   
    }
   
  
    
public static void main(String[] args) {   
        WaitAllSubThread wast 
= new WaitAllSubThread(10);   
        wast.run();   
    }
   
}


如果不用join,上面的代码会使先输出“main run end”,原因是:main 与 所有sub thread并发工作,不等待所有子线程继续工作。而所有子线程完成了,main线程才会退出。
用比较笨的方式:把上面/* */的注释去掉,把 th.join();块注释掉。这样可以使等待所有子线程完成了才去执行其它后续的(比如:这里是输出“main run end”)。分析:程序中加工作的子线程的计数(liveThreadNum)。main不断轮询是否所有子线程完成,所有完成就执行剩下的。
上面的是昨天写的,今天发现一个更加简洁的方式去处理main线程阻塞(等待所有子线程),那就是java.util.concurrent.CountDownLatch类。现在重新实现上面的功能,CountDownLatchUse.java

package com.chenlb;   
  
import java.util.Random;   
import java.util.concurrent.CountDownLatch;   
  
/**  
 * 
@author chenlb 2008-11-1 下午11:43:31  
 
*/
  
public class CountDownLatchUse {   
  
    
final CountDownLatch downLatch;   
    
int n;  //工作线程数   
  
    
public CountDownLatchUse(int n) {   
        
this.downLatch = new CountDownLatch(n);   
        
this.n = n;   
    }
   
  
    
class Worker implements Runnable {   
  
        String name;   
        
int sleep;   
  
        
public Worker(String name, int sleep) {   
            
this.name = name;   
            
this.sleep = sleep;   
        }
   
  
        
public void run() {   
            System.out.println(name
+", start to work.");   
            
try {   
                Thread.sleep(sleep);    
//虚拟工作. 10s 随机时间   
            }
 catch (InterruptedException e) {   
                System.out.println(name
+" interrupted.");   
            }
   
            System.out.println(name
+", end to work ["+sleep+"] sleep.");   
            meDone();   
//某个工作线程完成   
        }
   
    }
   
  
    
private void meDone() {   
        downLatch.countDown();   
    }
   
  
    
public void run() {   
        System.out.println(
"-------------main run start-------------");   
        
int sleepSaid = 10 * 1000;  //每个工作线程虚拟工作最大时间   
        Random rm = new Random();   
        
for(int i=0; i<n; i++{   
            
new Thread(new Worker("worker-"+i, rm.nextInt(sleepSaid)+1)).start();   
        }
   
  
        
try {   
            downLatch.await();  
//等待所有工作线程完成.   
        }
 catch (InterruptedException e) {   
            System.out.println(
"main interrupted.");   
        }
   
        System.out.println(
"---------------main run end--------------");   
    }
   
  
    
public static void main(String[] args) {   
        CountDownLatchUse mtu 
= new CountDownLatchUse(10);   
        mtu.run();   
    }
   
}


CountDownLatch.countDown();完成线程的计数。CountDownLatch.await();完成了主线程阻塞。简洁就是好,以后就这种方式了。

posted on 2010-01-26 18:00 J2EE学习笔记 阅读(1189) 评论(0)  编辑  收藏 所属分类: 转载java

只有注册用户登录后才能发表评论。


网站导航: