`

java 多线程全部执行完后再继续进行后门的方法

阅读更多
今天面试一家互联网公司,被虐的有点体无完肤,后来查询资料来总结下。
我们知道,当不使用线程池时,想让A线程在B线程执行完之后执行,需要在A中的某个调用处,调用B.join,但如果使用jdk1.5以后提供的线程池ExecutorService,这个就用不上了,用了会出同步问题,其实这个场景应该是很常见的吧,比如你用多线程并发执行一些操作,当这些操作全部完成时才能进行下一步,这就是需要这个功能了。后来偶然在网上看到有人说用ExecutorService.invokeAll可以实现,测试了一下,确实简单。这个方法的定义如下:

[java] view plaincopy
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) 
       throws InterruptedException; 

    你需要传一个Callable实现类元素的集合给此方法,每个元素就是一个线程了,返回值是线程执行结果的集合,声明的异常,按照文档的说法---if interrupted while waiting, in which case unfinished tasks are cancelled,如果执行时出现了中断异常,其它未执行完的线程会取消,但我经过测试,发现并没有取消,仍旧正常执行了。下面给出个小例子:

package com.lx.thread.afterAllThreadOver1;

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class InvokeAllTest {
public static void main(String[] args) throws Exception { 
        ExecutorService pool = Executors.newCachedThreadPool(); 
 
        ArrayList<Callable<Integer>> callers = new ArrayList<Callable<Integer>>(); 
        long tStart = System.currentTimeMillis(); 
        int len = 200; 
        final Random rnd = new Random(System.currentTimeMillis()); 
        for (int i = 0; i < len; i++) { 
            callers.add(new Callable() { 
                public Object call() throws Exception { 
                    String name = Thread.currentThread().getName(); 
                    int num = rnd.nextInt(10); 
                    //如果生成的随机数大于5,就抛出个异常, 
                    //但此异常并不会被主程序catch到,谁能告诉我为什么??? 
                    if (num > 5) { 
                        System.out.println("exception:----"); 
                        throw new InterruptedException(name); 
                    } 
                    Thread.sleep(10000); 
                    System.out.println(name); 
                    return null; 
                } 
            }); 
        } 
        pool.invokeAll(callers); 
        long tEnd = System.currentTimeMillis(); 
        System.out.println("总共用时:"+ (tEnd - tStart) + "millions"); 
        System.out.println("done!"); 
        pool.shutdown(); 
    } 
}




逻辑极其简单,启动200个线程,每个线程先生成一个随机数,如果大于5就抛出异常,中止,否则,睡10秒钟,再输出自己的名字。如果输出结果是200条,说明不管有没有线程抛出异常,其它异常仍旧会照常执行,使用完毕后一定要记得shutdown线程池,否则程序一直挂在那儿无法终止。运行结果,done总是在最后一行输出,说明它总是等池里的所有线程执行完后才会执行到这一步,这样你就可以把第二步的逻辑写到这里就行了。解决了很大的问题。

  • 大小: 12.7 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics