线程池是并发包里的东西。
有个Executors工厂类,可以直接搞到我们常用的几个线程池对象,前提是对原理比较理解,才可以放心大胆的使用。
java之前有个Timer类,当定时器使。现在线程池也提供类类似的功能,有了这个,完全可以不用使用那个Timer类了。上一段代码
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
public void run() {
System.out.println("run");
}
},1,3, TimeUnit.SECONDS);
}
底层用的任务队列是DelayQueue,这样就很好理解其实现原理了。
自定义线程池需要注意的问题
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
有界队列:比如ArrayBlockingQueue。新来一个任务,如果此时任务数小于coreSize,那么会直接创建线程执行。如果任务数大于coreSize,小于maxSize,而且队列没满,则进入队列。如果队列满了,而且任务数小于maxSize,则创建线程执行。最后一种情况,线程数是maxSize,而且队列满了,执行拒绝策略。验证方法也很简单,自己根据上面的构造方法试一下就可以了。
无界队列:新来一个任务,在小于coreSize的时候,创建线程执行,如果线程数是coreSize,则进入队列等待。没有拒绝策略可以执行。直到耗尽资源。也就是说,跟maxSize没有毛关系。无界队列的瓶颈是coreSize。比如LinkedBlockingQueue
new ThreadPoolExecutor(1, 2, 30l, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5), new RejectedExecutionHandler() {
/**
*
* @param r 当前任务对象
* @param executor 当前线程池对象
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
//可能是线程比较忙的原因拒绝,可以等一会儿,再次提交
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executor.execute(r);
}
});