线程池应用编程实现
使用固定大小的线程池
public class Test1 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService es = Executors.newFixedThreadPool(3);
//计算1+2+3+……+1000,启动10个工作任务
Future [] fs = new Future[10];
for (int i = 0; i < 10; i++) {
int begin =i*100+1;
int end =(i+1)*100;
Callable<Integer> caller = new MyCallable(begin,end);
fs[i]=es.submit(caller);
}
int res=0;
for (int i = 0; i < fs.length; i++) {
Object kk = fs[i].get();
if (kk!=null && kk instanceof Integer ) {
res+=(Integer)kk;
}
}
es.shutdown();
System.out.println("1+2+3+……+1000="+res);
}
}
class MyCallable implements Callable<Integer>{
private int begin,end;
public MyCallable(int begin,int end) {
this.begin=begin;
this.end=end;
}
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread());
int res=0;
for (int i = begin; i < end; i++) {
res+=i;
}
return res;
}
}
使用缓存线程池
public class Test2 {
public static void main(String[] args) throws Exception {
ExecutorService es = Executors.newCachedThreadPool();
// 计算1+2+3+……+1000,启动10个工作任务
Future[] fs = new Future[10];
for (int i = 0; i < 10; i++) {
int begin = i * 100 + 1;
int end = (i + 1) * 100;
Callable<Integer> caller = new MyCallable(begin, end);
fs[i] = es.submit(caller);
}
int res = 0;
for (int i = 0; i < fs.length; i++) {
Object kk = fs[i].get();
if (kk != null && kk instanceof Integer) {
res += (Integer) kk;
}
}
es.shutdown();
System.out.println("1+2+3+……+1000=" + res);
}
}
class MyCallable implements Callable<Integer> {
private int begin, end;
public MyCallable(int begin, int end) {
// TODO Auto-generated constructor stub
this.begin = begin;
this.end = end;
}
@Override
public Integer call() throws Exception {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread());
int res = 0;
for (int i = begin; i < end; i++) {
res += 1;
}
return res;
}
}
ThreadPoolExecutor
在具体开发中一般不建议直接使用系统预定义的线程池【ali】,而是通过ThreadPoolExecutor进行自定
义线程池
ThreadPoolExecutor是线程池框架的一个核心类,线程池提供了线程对象的复用机制,并对线程进行统
一管理
1.降低系统资源消耗
2.提高响应速度
3.提高线程的可管理性
线程池的运行状态有5种
1.Running高3位位111,可以接收新任务并处理阻塞队列中的任务
2.shutdown高3位为000,不接收新任务但是会处理阻塞队列中的任务
3.stop高3位为001,不会接收新任务,也不会处理阻塞队列中的任务,并且中断正在运行的任务
4.tidying高3为010,所有任务都终止,工作线程数为0
5.terminated高3为011,中断任务执行阶段结束
构造器函数
1 2 3 4 5 | public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } |
构造器定义
1 2 3 4 | public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) } |
1.corePoolSize用于配置线程池中核心线程数
2.maximumPoolSize用于设置线程池中允许的最大线程数。当阻塞队列满了之后,继续提交任务则
创建性的线程执行任务
3.keepAliveTime用于配置空闲线程的存活时间。默认情况下只有当线程池的线程数大于
corePoolSize这个参数才会生效。当一个工作线程的空闲时间到达这个值时,这个线程会自动终
止,直到线程数不超过corePoolSize为止。一般核心线程不会自动终止,除非调用方法
allowCoreThreadTimeout(boolean)配置
4.unit就是keepAliveTime参数的时间单位,是一个枚举类型值
5.workQueue任务缓存队列,用于存放等待执行的任务。如果当前线程数为corePoolSize时,继续
提交的任务就会被缓存到任务队列中,等待被调度执行。
1.SynchronousQueue是一个不存储元素的阻塞队列,每个插入操作必须等待另外线程调用移
除操作,否则插入操作一直处于阻塞等待状态
2.LinkedBlockingQueue是一种基于链表结构的阻塞队列,是一种无界队列
3.ArrayBlockingQueue是一个基于数组结构的有界阻塞队列,会按照FIFO的规则排序任6.ThreadFactory线程工作,用于创建新线程时使用的工厂类
7.handler设置任务拒绝策略,当阻塞队列满,而且线程池中线程数已经到达了maximumPoolSize,
如果继续提交任务,就会采用任务拒绝策略处理新任务
1.AbortPolicy丢弃任务,并且抛出异常,是默认拒绝策略
2.CallerRunsPolicy由调用execute方法提交任务的线程自己执行任务
3.DiscardPolicy丢弃任务,但是不抛出异常
4.DiscardOldestPolicy 丢弃任务队列中最前面的任务,然后重新尝试执行任务
同时也允许根据应用场景实现RejectedExecutionHandler接口自定义饱和策略,例如记录日志或者
持久化存储不能处理的任务
Executors:
Executors是一个用户创建线程池的工具类
1.newFixedThreadPool用于创建一个固定大小的定长线程池,可以控制线程的最大并发数,超出的
线程会在队列中等待
1.因为采用的是无界队列,而且实际线程数永远不会变化,适用于可以预测线程数量的业务中,
或者服务器负载较重的场景下,对当前的线程数量进行限制
2.由于是无界队列可以会导致大量的任务积压
1 2 3 4 5 6 | public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()); //核心线程数=最大线程数,所以keepAliveTime设置无效,任务队列采用 //LinkedBlockingQueue无界队列 } |
2.newCachedThreadPool用于创建一个可缓存的线程池,如果线程池长度超过处理需求,可以灵活
的回收空闲线程资源,如果没有可回收重用线程时会自动新建线程
1.可以用来创建一个可以无限扩大的线程池(最大线程数Integer.MAX_VALUE),适用于服务
器负载较轻,执行很多短期异步任务的场景下
1 2 3 4 5 6 | public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); //核心线程数0<最大线程数Integer.MAX_VALUE,所以keepAliveTime设置有效,一个线程最 //大空闲时间为60s } |
3.newSingleThreadExecutor用于创建只有一个线程的定长线程值,只用唯一的工作线程来执行任
务,保证所有的任务按照FIFO或者LIFO顺序执行
1.适用于需要保证顺序执行各个任务的场景下,而且需要保证在任意的时间点上不会出现多个任
务同时执行
1 2 3 4 5 | public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())); 核心线程数1=<最大线程数1,所以所以keepAliveTime设置无效,任务队列采用 //LinkedBlockingQueue无界队列 |
4.newScheduledThreadPool创建一个变长的线程池,并且支持定时及周期性任务的执行
1.可以延时启动、定时执行的线程池,适用于需要多个后台线程执行周期性任务的场景下
1 2 3 4 5 6 7 8 9 10 | public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue()); } |
5.newWorkStealingPool创建一个拥有多个任务队列的线程池
创建当前可用cpu数量的线程来并行执行,适用于比较耗时的操作同时并行执行的场景下
提交任务的方式
线程池提供了2种任务提交方法submit和execute,一般通过submit提交任务是用于可以有返回值的时
候,通过execute提交的任务不能获取任务的执行结果
execute的方法
public class Test3 {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(3);
es.execute(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("Hello " + i);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
System.out.println("main........");
}
}
submit的方法
public class Test4 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService es = Executors.newFixedThreadPool(3);
es.submit(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("Hello " + i);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
System.out.println("main........");
ExecutorService es1 = Executors.newFixedThreadPool(3);
Future f = es1.submit(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("Hello " + i);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
f.get(); // 可以通过get接收子线程的执行结果,也可以到达阻塞主线程,等待子线程执行完成的效果
System.out.println("main........");
}
}