共计 2831 个字符,预计需要花费 8 分钟才能阅读完成。
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 的结构器及七个参数的意义,同时也论述了四种回绝策略的作用及原理。
正文完