关于Executors创建和管理线程的那些事

来源:互联网 发布:此网络受法律保护 编辑:程序博客网 时间:2024/05/24 06:45

线程是并发最基本的单元。Java线程本质上被映射到操作系统线程,并且每个线程对象对应着一个计算机底层线程。

来张图说明一下:


1.自己管理线程并不是很好的选择,最大劣势是,你很容易过分的关注线程的数量。线程是很昂贵的对象,创建它们需要耗费大量的内存和时间。线程太少,你不能获得良好的并发性;线程太多,将很可能导致内存问题,调度也变得更复杂。
2.幸运的是,JVM为我们提供了线程管理的功能,它就是Executor接口。JAVA1.5后引入的Executor框架的最大优点是把任务的提交和执行解耦。
Executor接口的定义非常简单:


public interface Executor {

 
         void execute(Runnable command);
 
}
它隐藏了如何处理Runnable的细节。作为开发者,我们只需要给它任务,Executor自会处理它。
Executors类提供了一组方法,能够创建拥有完善配置的线程池和executor。我们将使用newFixedThreadPool()创建预定义数量的线程,并不允许线程数量超过这个预定义值。这意味着,如果所有的线程都被使用的话,提交的命令将会被放到一个队列中等待;当然这是由executor来管理的。
如果你需要精确的控制程序产生的线程数量,以及它们的精确行为,那么executor和executor服务将是正确的选择。对于大型系统,我个人认为使用executor最合适。


3.Executor框架主要包含以下3个部分:
(1)任务:包括Runnable和Callable,其中Runnable表示一个可以异步执行的任务,而Callable表示一个会产生结果的任务
(2)执行:包括Executor框架的核心接口Executor以及其子接口ExecutorService。
(3)计算的结果:包括接口Future和其实现类FutureTask。


ThreadPoolExecutor类(java.util.concurrent.ThreadPoolExecutor):
它是线程池的核心实现类,用来执行被提交的任务。
它通常由工厂类Executors来创建,Executors可以创建单线程执行SingleThreadExecutor,固定线程数量线程池FixedThreadPool以及无限制线程数量线程池CachedThreadPool等不同的ThreadPoolExecutor。
举例,创建实例:
        ExecutorService executorService = Executors.newCachedThreadPool();
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        ExecutorService executorService = Executors.newSingleThreadExecutor();
关闭线程: executorService.shutdown();


使用Callable,Future返回结果
Future<V>代表一个异步执行的操作,通过get()方法可以获得操作的结果,如果异步操作还没有完成,则,get()会使当前线程阻塞。FutureTask<V>实现了Future<V>和Runable<V>。Callable代表一个有返回值得操作。
ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。
举例:
1. public class MytestExectorService {  
2.  
3.    private ExecutorService exec;  
4.    private int cpuCoreNumber;  
5.    private List<Future<Long>> tasks = new ArrayList<Future<Long>>();  
6.  
7.      
8.    class SumCalculator implements Callable<Long> {  
9.        private int[] numbers;  
10.        private int start;  
11.        private int end;  
12.  
13.        public SumCalculator(final int[] numbers, int start, int end) {  
14.            this.numbers = numbers;  
15.            this.start = start;  
16.            this.end = end;  
17.        }  
18.  
19.        public Long call() throws Exception {  
20.            Long sum = 0l;  
21.            for (int i = start; i < end; i++) {  
22.                sum += numbers[i];  
23.            }  
24.            return sum;  
25.        }  
26.    }  
27.  
28.    public MytestExectorService() {  
29.        cpuCoreNumber = Runtime.getRuntime().availableProcessors();  
30.        exec = Executors.newFixedThreadPool(cpuCoreNumber);  
31.    }  
32.  
33.    public Long sum(final int[] numbers) {  
34.       
35.        for (int i = 0; i < cpuCoreNumber; i++) {  
36.            int increment = numbers.length / cpuCoreNumber + 1;  
37.            int start = increment * i;  
38.            int end = increment * i + increment;  
39.            if (end > numbers.length)  
40.                end = numbers.length;  
41.            SumCalculator subCalc = new SumCalculator(numbers, start, end);  
42.            FutureTask<Long> task = new FutureTask<Long>(subCalc);  
43.            tasks.add(task);  
44.            if (!exec.isShutdown()) {  
45.                exec.submit(task);  
46.            }  
47.        }  
48.        return getResult();  
49.    }  
50.  
51.  
56.    public Long getResult() {  
57.        Long result = 0l;  
58.        for (Future<Long> task : tasks) {  
59.            try {  
60.                // 如果计算未完成则阻塞  
61.                Long subSum = task.get();  
62.                result += subSum;  
63.            } catch (InterruptedException e) {  
64.                e.printStackTrace();  
65.            } catch (ExecutionException e) {  
66.                e.printStackTrace();  
67.            }  
68.        }  
69.        return result;  
70.    }  
71.  
72.    public void close() {  
73.        exec.shutdown();  
74.    }  
75. }  
main方法:
public static void main(String[] args) throws ExecutionException {
     int[] numbers = new int[] { 1, 2, 0,,22,3, 4, 5, 6, 8 };  
MytestExectorService calc = new MytestExectorService();  
Long sum = calc.sum(numbers);  
System.out.println(sum);  
calc.close();  
}