测试代码
public class rejectHandler { public static void main(String[] arg){ Random random = new Random(); Executor executor = new ThreadPoolExecutor(2, // 线程池驻留线程数量 6, // 线程池最大线程数量 1, // 线程回收延时 SECONDS, // 线程回收延时单位 new LinkedBlockingQueue<Runnable>(10), // 大小为10的缓冲区 Executors.defaultThreadFactory(), // 设置创建线程的工厂为默认 new selfdefinedRejectionPolicy()); // 重写的任务拒绝策略 while(true) { try { // 模拟任务线程 ((ThreadPoolExecutor) executor).submit(() -> { try { System.out.println("-------------------------"); System.out.println("Blocking Queue Size: "+((ThreadPoolExecutor) executor).getQueue().size()); System.out.println("Number of Threads: "+((ThreadPoolExecutor) executor).getPoolSize()); // long sleep = Math.abs((long)random.nextInt()/1000000); // Thread.sleep(sleep); // System.out.println("Having slept for " + sleep + "miliseconds."); Thread.sleep(3000); } catch (Exception e) { e.printStackTrace(); } }); Thread.sleep(500); }catch (InterruptedException e1){ e1.printStackTrace(); } } } }
代码中我们启了一个自己的线程池,第一个系数是线程池中驻留的线程数,如果系统的任务存在没有任务的较长期的空闲时间,建议设为0以节省系统资源;如果系统中来任务较为频繁建议设置一定数量的驻留线程。线程池最大线程数量为这系统的最大容量,当任务到来频繁时,可能需要增加线程数量以容纳更多的任务执行。但是,系统资源是有限的,为了是系统不至于崩溃,建议设置一个最大值以防止某些极限场景摧毁整个系统。当任务数量超过系统承受能力时,多余的任务会被压入一个缓冲队列,如果你的系统时不时会有像DDOS一样的任务潮,建议使用链式队列(链表动态扩容)并将这个队列设置得长一些。当任务实在多得连缓冲队列都放不下时,会启动拒绝策略,Executor提供的拒绝策略有四种,最常用的是Abort(抛异常)和Discard(丢弃)策略,这里我们为了统计被丢弃的任务数量,重写了拒绝策略。
public class selfdefinedRejectionPolicy implements RejectedExecutionHandler { int count = 0; @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor e){ count++; System.out.println(count + "tasks have been discarded!"); } }
将加载任务和处理任务的时间分别设置为上面的时间(500ms加载一个任务,处理一个任务需要3s):
-------------------------
Blocking Queue Size: 9
Number of Threads: 5
37tasks have been discarded!
-------------------------
Blocking Queue Size: 9
Number of Threads: 5
-------------------------
Blocking Queue Size: 9
Number of Threads: 5
可以看到系统开启了全部5个线程,队列也基本占满。在3min中内丢弃了37个任务。这说明我们可能需要更大的线程容量了。
当然现实的情况肯定不是如此理想,可以使用真实的任务替换代码中的sleep过程。