线程池在Java并发编程中,有着举足轻重的位置,学习和掌握它是学习Java的重中之重。反正有空看看,学点知识,又不亏。编程
在开发中,合理使用线程池能带来什么好处呢?数组
线程池内部持有一个用于存储工做任务的队列,在核心线程满了时候,会将任务存储到队列中。经常使用队列类型:bash
ThreadPoolExecutor( int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
复制代码
在线程的构造方法中,共有5个参数:并发
Executors.defaultThreadFactory();
得到默认的线程工厂。主要做用就是给线程起个名字而已。//execute()方法执行任务
executor.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
});
//submit()方法提交任务
executor.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
}
});
复制代码
提交到线程池中有种方式:execute()方法和submit()方法。ide
execute()方法提交的任务没法得到返回值,没法判断提交状态。 submit()方法能够得到返回Future类型的对象,根据Future对象能够判断任务是否执行成功和经过get()方法得到返回值,但get()方法会阻塞当前线程一段时间。学习
SHUTDOWN
状态。而后中断全部没有正在执行任务的线程。STOP
状态。尝试中止全部正在执行或者暂停任务的线程,并返回等待执行任务的列表。因为二者都是遍历线程池中的工做线程,而后中断线程,因此没法响应中断的线程可能永远没法终止。ui
当咱们提交一个新任务到线程池时,任务在线程池的流程是怎样的呢?spa
任务队列的任务何时被处理?线程
线程池中线程处理任务有两种方式:一种就是新建线程处理任务,另外一种就是循环从阻塞队列获取任务来执行。code
有时咱们仅仅是使用一下线程池,不会本身定制线程池,毕竟线程池的构造方法参数那么多,个人妈耶。那看看类Executors提供的四个线程池。
//建立FixedThreadPool线程池
Executors.newFixedThreadPool(nThreads);
//newFixedThreadPool方法的实现
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
复制代码
建立一个FixedThreadPool线程池,线程的核心线程coreThreadSize和线程池线程容量maximumPoolSize都为nThreads。因为使用的无界的LinkedBlockingQueue队列,将致使maximumPoolSize参数失效,队列对任务未来者不拒。这里将保活时间设为0,意味着空线程会被当即终止。
//建立CachedThreadPool线程池
Executors.newCachedThreadPool();
//newCachedThreadPool方法的实现
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
复制代码
CachedThreadPool的核心线程为0,线程池容量为Integer.MAX_VALUE,意味着maximumPoolSize是无界的。保活时间keepAliveTime设为60秒,空闲线程闲置60秒后被终止。因为使用了没有容量的SynchronousQueue队列,意味当提交一个新任务到线程池中,没有空闲线程来对接,就会新建新的线程来处理新任务。
//建立SingleThreadExecutor线程池
Executors.newSingleThreadExecutor();
//SingleThreadExecutor方法的实现
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
复制代码
能够看到SingleThreadExecutor能够看作定制化的FixedThreadPool,将nThreads置为1,将核心线程和线程池容量设为1,以保证只有一个线程在执行。
//建立ScheduledThreadPool线程池
Executors.newScheduledThreadPool(corePoolSize);
//newScheduledThreadPool方法的实现
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
//ScheduledThreadPoolExecutor方法的实现
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
复制代码
newScheduledThreadPool方法最终会调用ThreadPoolExecutor的构造来建立线程池。将定制化DelayQueue后的DelayedWorkQueue做为工做队列。DelayedWorkQueue队列会把执行时间小的任务排在前面优先执行。若是执行时间相同,就会优先执行提交时间早的任务。
在经过submit()
方法提交任务到线程池,会返回有结果的Future类型的对象。Future是一个接口,FutureTask继承它,因此FutureTask也能够做为submit()
方法得返回值。同时,FutureTask继承Runnable接口,这样又能够做为任务提交到线程池中,由调用线程直接执行。
当调用FutureTask的get()
方法,若是FutureTask处于已完成状态(执行完毕),则会致使调用线程当即放回或者抛出异常。不然会使调用线程阻塞。
当调用FutureTask的cancel()
方法,若是FutureTask处于未启动状态(为执行run方法),则该任务不会被执行;若是处于启动状态,会尝试以中断来尝试中止任务。若是已经完成状态,则返回false。
经过对线程池知识点理解,能够清晰掌握建立线程池骚姿式和内涵。觉得实战提供必要的理论知识。
本文是我的学习总结和知识备忘,如知识有误或片面,请多加指正,谢谢
知识来源《Java并发编程的艺术》& 互联网 & 《Java并发编程实战》