提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
线程池复习梳理
线程池其实就是一个容纳多个线程的容器,其中线程可以反复利用,省去了频繁创建线程对象的操作,无序
合理利用线程池能够带来三个好处:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
可以看到这个类的构造器,包含了一些参数。
稍后解释这些参数的含义
corePoolSize:指定线程池的核心线程数量。
maximumPoolSize:指定线程池最大线程数量。
keepAliveTime:指定临时线程的存活时间。(临时线程闲置了**时间后就会被干掉)
unit:指定临时线程的存活时间单位。
workQueue:指定线程池的任务队列。
threadFactory:指定线程池的线程工厂。(指定哪个线程工厂来创建)
handler:指定线程池的任务拒绝策略(线程都在忙,任务队列也满了的时候,新来的任务该如何处理)。
例子
public static void main(String[] args) {
/* public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {*/
ExecutorService pool = new ThreadPoolExecutor(3, 5, 8, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
}
下面用一个例子来说明:
先创建一个Runnable任务
public class MineRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"==> 输出666");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
在主线程中创建线程池,并且分配执行
public class ThreadPoolsDemo01 {
public static void main(String[] args) {
/* public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {*/
ExecutorService pool = new ThreadPoolExecutor(3, 5, 8, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
MineRunnable target = new MineRunnable();
pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
pool.execute(target); //复用核心线程,执行任务
pool.execute(target); //复用核心线程,执行任务
}
}
我们增加几个线程去填满等待队列试试看:
pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
pool.execute(target); //线程池会自动创建一个新线程,自动处理这个任务,自动执行!
pool.execute(target); //复用核心线程,执行任务
pool.execute(target); //复用核心线程,执行任务
pool.execute(target); //复用核心线程,执行任务
pool.execute(target); //复用核心线程,执行任务
pool.execute(target); //复用核心线程,执行任务
可以看到多了几个临时线程。
那我们再次添加呢?
可以看到这里抛出了异常,这就是任务拒绝策略,当前使用的拒绝策略是直接丢弃任务,并且抛出异常。
以上代码都是使用AbortPolicy的结果
当我们改成CallerRunsPolicy呢?
可以看到,主线程也开始输出了
public class MineCallable implements Callable {
private int n;
public MineCallable(int n) {
this.n = n;
}
@Override
public String call() throws Exception {
int sum = 0;
for (int i = 0; i<n;i++){
sum += i;
}
return Thread.currentThread().getName()+ "==>" + n + "数求和的结果是:" + sum;
}
}
public class MineCallable implements Callable {
private int n;
public MineCallable(int n) {
this.n = n;
}
@Override
public String call() throws Exception {
int sum = 0;
for (int i = 0; i<n;i++){
sum += i;
}
return Thread.currentThread().getName()+ "==>" + n + "数求和的结果是:" + sum;
}
}
//通过Executors创建一个线程对象
ExecutorService pool1 = Executors.newFixedThreadPool(3);
OOM:内存溢出异常
Executors创建的线程,会因为任务过多/创建线程过多,导致内存溢出。
前两者会导致任务过多堆积
最后的Cached,多少任务进入多少线程就会被创建
注意:
这些方法的底层,都是通过线程池实现类ThreadExecutor创建的线程池对象。