背景
本文不是讲述线程池的基本知识,而是在做爬虫项目实际情况,碰到技术解决方案,简单的线程隔离的实践,在做爬虫时,会碰到反应慢和反应快的各种网站,如何同时用一个线程池去做爬虫请求,慢的网站会堵塞快的网站请求,这是就考虑线程隔离。线程池基于newFixedThreadPool()创建。
本文部分描述性内容来源于网络,其中示例性Java源代码经过本人亲自测试,如有不当、错误或侵权行为敬请指正。
基于下图:

ps:这小伙只是提供具体实现方案,没看到具体代码,只能自己实现了!
实现功能:
DynamicAsyncTaskService.java
/** * 动态线程池 * @author wuche * @version 暂时固定写死的,后期可以改造成基于spring建实例模式,或者基于懒加载模式创建 */ public class DynamicAsyncTaskService { private static DynamicAsyncTaskService service; //最大线程数(可以放使用多个) public static int executorPoolSize =10; //最大线程数(可以放少的) public static int executorPoolSize2 =5; //线程前缀名 public static String poolName ="1"; //线程前缀名 public static String poolName2 ="2"; private ThreadPoolExecutor pool = (ThreadPoolExecutor) Executors.newFixedThreadPool(executorPoolSize, setThreadFactory(poolName)); private ThreadPoolExecutor pool2 = (ThreadPoolExecutor) Executors.newFixedThreadPool(executorPoolSize2, setThreadFactory(poolName2)); public static DynamicAsyncTaskService getInstance() { if (service == null) { service = new DynamicAsyncTaskService(); } return service; } private ThreadFactory setThreadFactory(String poolName){ return new DefaultThreadFactory(poolName); } private ThreadPoolExecutor getPool(int i){ ThreadPoolExecutor newPool=null; if(i==1){ newPool=pool; }else{ newPool=pool2; } return newPool; } private int getPoolSize(int i){ int poolSize=executorPoolSize; if(i==1){ poolSize=executorPoolSize; }else{ poolSize=executorPoolSize2; } return poolSize; } /** * 获取可以使用线程数 * @param i * @return */ public int getAvailableNum(int i) { return getPoolSize(i)-getPool(i).getActiveCount(); } /** * 获取活动线程数 * @param i * @return */ public int getActiveNum(int i) { return getPool(i).getPoolSize(); } /** * 正在排队的线程数 * @return */ public int getQueueNum(int i) { return getPool(i).getQueue().size(); } public void execute(Runnable command,int i) { getPool(i).execute(command); } @SuppressWarnings({ "rawtypes", "unchecked" }) public Future submit(Callable task,int i) { return getPool(i).submit(task); } @SuppressWarnings("rawtypes") public Future submit(Runnable task, Object result,int i) { return getPool(i).submit(task, result); } /** * 自定义的ThreadFactory,便于日志打印 * @author wuche * */ static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private String namePrefix; DefaultThreadFactory(String poolName) { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool"+poolName +"-"+ poolNumber.getAndIncrement() + "-thread-"; } // 为线程池创建新的任务执行线程 public Thread newThread(Runnable r) { // 线程对应的任务是Runnable对象r Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(), 0); // 设为非守护线程 if (t.isDaemon()) t.setDaemon(false); // 将优先级设为Thread.NORM_PRIORITY if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } public String getNamePrefix() { return namePrefix; } public void setNamePrefix(String namePrefix) { this.namePrefix = namePrefix; } } }
测试类:TestAsyncTask.java
package com.haohan.thread; public class TestAsyncTask { public static void main(String[] args){ for (int i = 0; i < 35; i++) { final long startTime=System.currentTimeMillis(); if(i%2==0){ System.out.println("线程一开始::---"); DynamicAsyncTaskService.getInstance().execute(new Runnable() { @Override public void run() { try { System.out.println("正在运行线程名字:"+Thread.currentThread().getName()); System.out.println("线程池中现在的线程数目是:"+DynamicAsyncTaskService.getInstance().getActiveNum(1)+",队列中正在等待执行的任务数量为:"+ DynamicAsyncTaskService.getInstance().getQueueNum(1) +",可利用的线程数目:"+DynamicAsyncTaskService.getInstance().getAvailableNum(1) ); Thread.currentThread().sleep(1000); long endTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+"结束时间"+(endTime-startTime)); System.out.println("线程池中现在的线程数目是:"+DynamicAsyncTaskService.getInstance().getActiveNum(1)+",队列中正在等待执行的任务数量为:"+ DynamicAsyncTaskService.getInstance().getQueueNum(1) +",可利用的线程数目:"+DynamicAsyncTaskService.getInstance().getAvailableNum(1) ); } catch (InterruptedException e) { e.printStackTrace(); } } },1); }else{ DynamicAsyncTaskService.getInstance().execute(new Runnable() { @Override public void run() { try { System.out.println("正在运行线程名字:"+Thread.currentThread().getName()); System.out.println("线程池中现在的线程数目2是:"+DynamicAsyncTaskService.getInstance().getActiveNum(2)+",队列中正在等待执行的任务2数量为:"+ DynamicAsyncTaskService.getInstance().getQueueNum(2) +",可利用的线程2数目:"+DynamicAsyncTaskService.getInstance().getAvailableNum(2) ); Thread.currentThread().sleep(1000); long endTime=System.currentTimeMillis(); System.out.println(Thread.currentThread().getName()+"结束时间"+(endTime-startTime)); System.out.println("线程池中现在的线程数目是:"+DynamicAsyncTaskService.getInstance().getActiveNum(1)+",队列中正在等待执行的任务数量为:"+ DynamicAsyncTaskService.getInstance().getQueueNum(1) +",可利用的线程数目:"+DynamicAsyncTaskService.getInstance().getAvailableNum(1) ); } catch (InterruptedException e) { e.printStackTrace(); } } },2); } } /*System.out.println(Runtime.getRuntime().availableProcessors());*/ } }
测试结果:
线程一开始::--- 正在运行线程名字:pool1-1-thread-1 线程池中现在的线程数目是:1,队列中正在等待执行的任务数量为:0,可利用的线程数目:9 线程一开始::--- 正在运行线程名字:pool2-2-thread-1 线程池中现在的线程数目2是:1,队列中正在等待执行的任务2数量为:0,可利用的线程2数目:4 正在运行线程名字:pool1-1-thread-2 线程池中现在的线程数目是:2,队列中正在等待执行的任务数量为:0,可利用的线程数目:8 线程一开始::--- 正在运行线程名字:pool2-2-thread-2 线程池中现在的线程数目2是:2,队列中正在等待执行的任务2数量为:0,可利用的线程2数目:3 正在运行线程名字:pool1-1-thread-3 线程池中现在的线程数目是:3,队列中正在等待执行的任务数量为:0,可利用的线程数目:7 线程一开始::--- 正在运行线程名字:pool2-2-thread-3 线程池中现在的线程数目2是:3,队列中正在等待执行的任务2数量为:0,可利用的线程2数目:2 线程一开始::--- 正在运行线程名字:pool2-2-thread-4 线程池中现在的线程数目2是:4,队列中正在等待执行的任务2数量为:0,可利用的线程2数目:1 线程一开始::--- 正在运行线程名字:pool1-1-thread-5 线程池中现在的线程数目是:6,队列中正在等待执行的任务数量为:0,可利用的线程数目:4 正在运行线程名字:pool1-1-thread-4 线程池中现在的线程数目是:6,队列中正在等待执行的任务数量为:0,可利用的线程数目:4 正在运行线程名字:pool2-2-thread-5 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:1,可利用的线程2数目:0 线程一开始::--- 正在运行线程名字:pool1-1-thread-6 线程池中现在的线程数目是:7,队列中正在等待执行的任务数量为:0,可利用的线程数目:3 线程一开始::--- 正在运行线程名字:pool1-1-thread-7 线程池中现在的线程数目是:8,队列中正在等待执行的任务数量为:0,可利用的线程数目:2 线程一开始::--- 线程一开始::--- 正在运行线程名字:pool1-1-thread-9 线程一开始::--- 正在运行线程名字:pool1-1-thread-8 线程一开始::--- 线程一开始::--- 线程一开始::--- 线程一开始::--- 线程一开始::--- 线程一开始::--- 线程一开始::--- 正在运行线程名字:pool1-1-thread-10 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:8,可利用的线程数目:0 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:0 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:1,可利用的线程数目:0 pool1-1-thread-1结束时间1008 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:8,可利用的线程数目:0 正在运行线程名字:pool1-1-thread-1 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:7,可利用的线程数目:0 pool1-1-thread-2结束时间1000 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:7,可利用的线程数目:0 正在运行线程名字:pool1-1-thread-2 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:6,可利用的线程数目:0 pool2-2-thread-1结束时间1010 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:6,可利用的线程数目:0 正在运行线程名字:pool2-2-thread-1 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:11,可利用的线程2数目:0 pool2-2-thread-3结束时间1000 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:6,可利用的线程数目:0 正在运行线程名字:pool2-2-thread-3 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:10,可利用的线程2数目:0 pool2-2-thread-2结束时间1001 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:6,可利用的线程数目:0 正在运行线程名字:pool2-2-thread-2 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:9,可利用的线程2数目:0 pool1-1-thread-3结束时间1002 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:6,可利用的线程数目:0 正在运行线程名字:pool1-1-thread-3 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:5,可利用的线程数目:0 pool2-2-thread-4结束时间1001 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:5,可利用的线程数目:0 正在运行线程名字:pool2-2-thread-4 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:8,可利用的线程2数目:0 pool2-2-thread-5结束时间1001 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:5,可利用的线程数目:0 正在运行线程名字:pool2-2-thread-5 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:7,可利用的线程2数目:0 pool1-1-thread-4结束时间1002 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:5,可利用的线程数目:0 正在运行线程名字:pool1-1-thread-4 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:4,可利用的线程数目:0 pool1-1-thread-6结束时间1002 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:4,可利用的线程数目:0 正在运行线程名字:pool1-1-thread-6 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:3,可利用的线程数目:0 pool1-1-thread-9结束时间1003 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:3,可利用的线程数目:0 正在运行线程名字:pool1-1-thread-9 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:2,可利用的线程数目:0 pool1-1-thread-10结束时间1003 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:2,可利用的线程数目:0 正在运行线程名字:pool1-1-thread-10 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:1,可利用的线程数目:0 pool1-1-thread-7结束时间1005 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:1,可利用的线程数目:0 正在运行线程名字:pool1-1-thread-7 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:0 pool1-1-thread-8结束时间1005 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:0 pool1-1-thread-5结束时间1007 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:1 pool1-1-thread-1结束时间1987 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:2 pool2-2-thread-1结束时间1997 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:3 正在运行线程名字:pool2-2-thread-1 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:6,可利用的线程2数目:0 pool1-1-thread-2结束时间1996 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:3 pool2-2-thread-3结束时间1997 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:4 正在运行线程名字:pool2-2-thread-3 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:5,可利用的线程2数目:0 pool1-1-thread-4结束时间2001 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:4 pool2-2-thread-5结束时间2001 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:5 正在运行线程名字:pool2-2-thread-5 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:4,可利用的线程2数目:0 pool2-2-thread-2结束时间2003 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:5 正在运行线程名字:pool2-2-thread-2 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:3,可利用的线程2数目:0 pool1-1-thread-3结束时间2003 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:5 pool2-2-thread-4结束时间2003 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:6 正在运行线程名字:pool2-2-thread-4 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:2,可利用的线程2数目:0 pool1-1-thread-6结束时间2003 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:6 pool1-1-thread-9结束时间2003 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:7 pool1-1-thread-10结束时间2004 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:8 pool1-1-thread-7结束时间2005 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:9 pool2-2-thread-1结束时间2996 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:10 正在运行线程名字:pool2-2-thread-1 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:1,可利用的线程2数目:0 pool2-2-thread-3结束时间2997 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:10 正在运行线程名字:pool2-2-thread-3 线程池中现在的线程数目2是:5,队列中正在等待执行的任务2数量为:0,可利用的线程2数目:0 pool2-2-thread-5结束时间3001 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:10 pool2-2-thread-4结束时间3003 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:10 pool2-2-thread-2结束时间3003 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:10 pool2-2-thread-1结束时间3996 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:10 pool2-2-thread-3结束时间3997 线程池中现在的线程数目是:10,队列中正在等待执行的任务数量为:0,可利用的线程数目:10
从以上结果可以看出,newFixedThreadPool的参数指定了可以运行的线程的最大数目,超过这个数目的线程加进去以后,不会立即运行,而是被放入任务队列中等待执行。其次,加入线程池的线程属于托管状态,线程的运行不受加入顺序的影响。并且两个线程池是不会相互影响的!
该场景可以用到需要多线程业务当中是没问题的!!