Java—Executor线程池
什么是线程池?
将若干线程放在一起,同一进行管理,调度,和监控(线程池就相当于 包工头)
为什么要有线程池?
线程池有如下的优点:
1.降低资源消耗:重复利用已有的线程,减少了不断创建销毁线程的资源消耗
2.提高响应速度:在任务到达时,不需要等待线程的创建就可以直接执行任务
3.便于管理:使用线程池可以统一进行线程的分配、调度管理
线程池构造方法的几个参数几个参数:
corePoolSize:核心线程池数
maximumPoolSize:最大线程池数
keepAliveTime:最大等待时间
BlockingQueue:工作队列
四种:ArrayBlockingQueue:底层用数组实现是一个FIFO队列
LinkedBlockingQueue:底层用链表实现FIFO,是一个无界限队列,吞吐量较大
SynchronousQueue:是一个不储存元素的无界队列,意思是,每个插入操作必须等待另一个线程的移除操 作,吞吐量比LinkedBlocking大
PriorityBlockingQueue:一个有优先级的无限阻塞队列
RejectedExecutionHandler:处理策略
四种:AbortPolicy(默认的处理策略,直接抛出异常)
CallerRunsPolicy(让调用其的线程执行)
DiscardOldestPolicy(丢弃线程池里最近的一个任务)
DiscardPolicy(不处理直接丢弃,也不会受到异常信息)
线程池的执行流程:
1.向线程池里添加任务,如果核心线程池没满,直接添加到核心线程池里执行任务;如果核心线程池满了,看核心线程池是否由空闲的线程,否则执行步骤2,
2.将任务封装成Work添加到工作队列中,如果工作队列没满,直接添加,如果满了执行步骤3
3.判断线程池的线程是否都处于工作状态,如果没有,创建一个新的工作线程,否则如果以满,执行饱和策略处理该任务。
线程池的创建
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
任务的提交:
有两种方法,
1.executor(Runnable Task)
2.sumbit(Runnable|Callable Task);
关闭线程池
shutdown() 不会立刻关闭只是设置了一个标志位,将所有没有执行任务的线程终止
shutdownNow() 终止所有线程
Executors ——Java提供的线程池
1.固定大小线程池:newFixedThreadPool
使用场景:用于为了满足资源管理需求而限制当前线程的数量的场景:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
这种创建线程池的方式,最大线程池数没有用,因为是一个LinkedBlickingQueue的无界队列。
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"start....");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"end....");
}
}
public class Test {
public static void main(String[] args) {
ExecutorService task=Executors.newFixedThreadPool(5);
for(int i=0;i<10;i++){
task.submit(new MyThread());
}
task.shutdown();
}
}
2.单线程池:newSingleExecutor();
使用场景:用于保证顺序的执行任务,并且在每个场景下只有单线程
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
工作队列还是一个无界队列,但是,线程数只有1,每次只会执行一个任务
public class Test {
public static void main(String[] args) {
ExecutorService task
=Executors.newSingleThreadExecutor();
for(int i=0;i<10;i++){
task.submit(new MyThread());
}
task.shutdown();
}
}
3.缓存线程池:newCatachThreadPool()
使用场景:根据需要创建线程的线程池,适合一些任务多,但业务逻辑简单的场景
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
工作队列是一个SynchronousQueue每插入一个元素,就会被线程池取走,如果60秒线程没有执行任务 终止。
1.如果提交任务速度高于任务处理速度,那么,线程将会不断被创建(资源消耗大)。
2.反之,已有线程的复用率高。
public class Test {
public static void main(String[] args) {
ExecutorService task=Executors.newCachedThreadPool();
for(int i=0;i<10;i++){
task.submit(new MyThread());
}
task.shutdown();
}
}
4.newScheduleThreadPool和Time功能类似(但后者是延期调度单线程的)
提交任务的方法 scheduleAtFixedRate() 周期性调度 和scheduleWithFixedDelay()
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "start");
}
}
public class Test {
public static void main(String[] args) {
ScheduledExecutorService task
=Executors.newScheduledThreadPool(5);
for (int i=0;i<5;i++){
task.scheduleAtFixedRate(new MyThread(),2,5,TimeUnit.SECONDS);
}
//注意,这里没有关闭线程池,如果关闭,那么一个线程也不会执行
}
}