【学习笔记】多线程编程-线程池/任务/线程 (2)

SynchronousQueue类型:所有任务不进入缓冲队列(可以理解为缓冲队列的容量为0),直接进入可用线程执行,当无可用线程时则直接创建新线程执行任务。当线程数超过M时,调用Handler处理被拒绝的新任务。

LinkedBlockingQueue类型:有新任务时,若当前线程数少于N,则创建新线程;若大于等于N,则进入缓冲队列;当缓冲队列充满时,且线程数少于M,则继续创建新线程,直至达到M时调用Handler处理拒绝任务。一般情况下,LinkedBlockingQueue作为无界队列不指定缓冲容量,可以无限扩展,此时相当于M失效;但也可以通过构造函数来指定容量。

ArrayBlockingQueue类型:规则与LinkedBlockingQueue类似,但一般情况下指定队列长度。

具体这三种队列类型的区别可以参考这篇文章:ThreadPoolExecutor的三种队列

还有超时时间T和时间单位U,主要作用在于令非核心线程闲置超过一定时长后自动销毁,从而释放资源。

拒绝任务Handler

当线程数和缓冲队列都达到饱和时,会调用相应的Handler处理拒绝的任务。以下是四种预定义的处理策略: 

在默认的AbortPolicy 中,拒绝后直接抛出异常RejectedExecutionException。

在CallerRunsPolicy 中,直接在 execute 方法的调用线程中运行被拒绝的任务。该策略提供简单的反馈控制机制,能够减缓新任务的提交速度。

在DiscardPolicy 中,拒绝后直接放弃任务。

在DiscardOldestPolicy 中,位于工作队列头部(即最旧)的任务将被放弃,然后重试执行程序(如果再次失败,则重复此过程)。

线程池的简单示例

以斐波那契数列为例,主要展示了不同任务类型的用法区别,注意此处使用submit而不是execute来提交任务,两者区别类似Callable和Runnable。

1 package com.effective.java.concurrent.task; 2 3 import java.util.concurrent.Callable; 4 import java.util.concurrent.ExecutionException; 5 import java.util.concurrent.ExecutorService; 6 import java.util.concurrent.Executors; 7 import java.util.concurrent.Future; 8 import java.util.concurrent.FutureTask; 9 10 public class RunnableFutureTask { 11 12 static ExecutorService mExecutor = new ThreadPoolExecutor(2, 3, 5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); 13 14 15 public static void main(String[] args) { 16 futureDemo(); 17 } 18 19 20 static void futureDemo() { 21 try { 22 /** 23 * 提交runnable则没有返回值, future没有数据 24 */ 25 Future<?> result = mExecutor.submit(new Runnable() { 26 27 @Override 28 public void run() { 29 fibc(20); 30 } 31 }); 32 33 System.out.println("future result from runnable : " + result.get()); 34 35 /** 36 * 提交Callable, 有返回值, future中能够获取返回值 37 */ 38 Future<Integer> result2 = mExecutor.submit(new Callable<Integer>() { 39 @Override 40 public Integer call() throws Exception { 41 return fibc(20); 42 } 43 }); 44 45 System.out 46 .println("future result from callable : " + result2.get()); 47 48 /** 49 * FutureTask可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行 50 * ,并且还可以通过v get()返回执行结果,在线程体没有执行完成的时候,主线程一直阻塞等待,执行完则直接返回结果。 51 */ 52 FutureTask<Integer> futureTask = new FutureTask<Integer>( 53 new Callable<Integer>() { 54 @Override 55 public Integer call() throws Exception { 56 return fibc(20); 57 } 58 }); 59 60 // 提交futureTask 61 mExecutor.submit(futureTask) ; 62 System.out.println("future result from futureTask : " 63 + futureTask.get()); 64 65 } catch (InterruptedException e) { 66 e.printStackTrace(); 67 } catch (ExecutionException e) { 68 e.printStackTrace(); 69 } 70 } 71 72 /** 73 * 效率底下的斐波那契数列, 耗时的操作 74 * 75 * @param num 76 * @return 77 */ 78 static int fibc(int num) { 79 if (num == 0) { 80 return 0; 81 } 82 if (num == 1) { 83 return 1; 84 } 85 return fibc(num - 1) + fibc(num - 2); 86 } 87 }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzjwwf.html