java并发编程实践阅读笔记之线程池的使用
当线程池的工作队列被填满后,如果没有预定义的饱和策略来阻塞任务的执行,则可以通过信号量Semaphore来限制任务的到达率。Semaphore是一个同步工具类,用来控制同时访问某个特定资源的操作数量。它的acquire方法返回一个虚拟的许可,如果没有可用的许可,则阻塞该方法的调用线程直到有可用许可为止。如果线程池使用无界队列缓冲任务时,如果任务在某一时间增长数量过快,容易导致内存耗尽。
无界队列和Semaphore搭配使用,通过设置信号量的上界,来控制任务的提交速率。使用上一章的MyCommand任务,结合Semaphore,代码如下:
/** * * @title :BoundedExecutor * @description :使用Semaphore控制任务的提交速率 * @since :2014-12-15 */ public class BoundedExecutor { private final Executor exec; private final Semaphore semaphore; public BoundedExecutor(Executor exec,int bound){ this.exec = exec; this.semaphore = new Semaphore(bound); } public void submitTask(final Runnable command) throws InterruptedException{ try{ semaphore.acquire(); exec.execute(new Runnable(){ @Override public void run() { try{ command.run(); }finally{ System.out.println("执行完成 ,release..."); semaphore.release(); } } }); }catch(RejectedExecutionException e){ System.out.println("队列已满,拒绝执行"); semaphore.release(); } } public static void main(String[] args) { //虽然线程池大小为4,但是Semaphore限制每次只能有两个任务被执行 Executor exec = Executors.newCachedThreadPool(); BoundedExecutor b = new BoundedExecutor(exec,2); MyCommand c1 = new MyCommand("c1"); MyCommand c2 = new MyCommand("c2"); MyCommand c3 = new MyCommand("c3"); MyCommand c4 = new MyCommand("c4"); MyCommand c5 = new MyCommand("c5"); try { b.submitTask(c1); b.submitTask(c2); b.submitTask(c3); b.submitTask(c4); b.submitTask(c5); } catch (InterruptedException execption) { execption.printStackTrace(); } } }
任务执行结果:
pool-1-thread-2 ,name: c2,Mon Dec 15 16:20:17 CST 2014 pool-1-thread-1 ,name: c1,Mon Dec 15 16:20:17 CST 2014 执行完成 ,release... 执行完成 ,release... pool-1-thread-1 ,name: c4,Mon Dec 15 16:20:22 CST 2014 pool-1-thread-3 ,name: c3,Mon Dec 15 16:20:22 CST 2014 执行完成 ,release... 执行完成 ,release... pool-1-thread-1 ,name: c5,Mon Dec 15 16:20:27 CST 2014 执行完成 ,release...
执行结果分析:使用Semaphore限制每次只能提交两个任务,任务完成后释放信号量许可,的确可以控制任务的提交速率。