java 中的池化技术能够在咱们开拓新的线程之前提前为咱们筹备好,从而缩小了零碎的开销。线程池帮咱们对线程对立治理,同时也进步了零碎的响应。jdk concurrent 中的 Executors 类为咱们提供了创立线程池的办法,简略易用。次要有以下几个办法:
- newFixedThreadPool(int nThreads) 固定线程数的线程池;
- newSingleThreadExecutor() 只产生单个线程的线程池;
- newCachedThreadPool 缓存类型的线程池,线程数量可伸缩,非固定;
先来说下,除了这些 jdk 给咱们封装好的办法外,咱们能够本人手动创立线程池,本人创立能够加深咱们对这部分常识的印象,咱们能够通过调用 ThreadPoolExecutor 的构造方法来创立:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
看下他的重载结构器:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
它的的构造方法中,次要有这么几个重要的参数:
- corePoolSize 线程池的外围线程数;
- maximumPoolSize 线程池的最大线程数;
- keepAliveTime 闲置线程存货工夫,超过这个工夫将会被回收(超过外围线程数的局部);
- unit 工夫单位;
- workQueue 阻塞队列,当线程数超过外围线程数时,工作将会被放入队列中;
- threadFactory 线程工厂,用于创立线程,个别应用它默认的外部类,ThreadPoolExecutor 没有提供该字段的 setter/getter 办法;
- handler 回绝策略,当阻塞队列满,并且超过最大线程数时,将会执行回绝策略的 reject 办法。
看一下线程池执行线程的 execute 办法:
public void execute(Runnable command) {if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 如果工作线程数小于外围线程数,调用 addWorker 办法后间接返回
if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))
return;
c = ctl.get();}
// 超过了外围线程数,优先增加到阻塞队列中
if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
// 阻塞队列满,新建线程(每个线程都是一个 worker)并增加到 workers。else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 阻塞队列满,并且线程数大于最大线程数,调用 handler 的 rejectedExecution 办法。else if (!addWorker(command, false))
reject(command);
}
再来看下线程池的回绝策略,ThreadPoolExecutor,有个属性 defaultHandler,即默认的回绝策略。该类型为 AbortPolicy:其 rejectedExecution 办法是抛出异样。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {throw new RejectedExecutionException("Task" + r.toString() +
"rejected from" +
e.toString());
}
DiscardPolicy:什么都不做,放弃本次的工作
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {}
DiscardOldestPolicy:摈弃后面的工作,把新的工作退出到缓存队列中:
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {
// 弹出最后面的工作
e.getQueue().poll();
// 执行新的工作
e.execute(r);
}
}
CallerRunsPolicy:由调用线程执行 run 办法:
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {
// 能够看到只是以后线程调用了 run 办法,并没有新建线程。r.run();}
}
小结:
次要简述了线程池罕用的创立办法、ThreadPoolExecutor 的结构器及七个参数的意义,同时也论述了四种回绝策略的作用及原理。