您的位置:首页 > 编程语言 > Java开发

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

2017-09-28 15:05 495 查看
线程是并发最基本的单元。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.
4000
       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();  

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息