背景
本文不是講述線程池的基本知識,而是在做爬蟲項目實際情況,碰到技術解決方案,簡單的線程隔離的實踐,在做爬蟲時,會碰到反應慢和反應快的各種網站,如何同時用一個線程池去做爬蟲請求,慢的網站會堵塞快的網站請求,這是就考慮線程隔離。線程池基于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的參數指定了可以運作的線程的最大數目,超過這個數目的線程加進去以後,不會立即運作,而是被放入任務隊列中等待執行。其次,加入線程池的線程屬于托管狀态,線程的運作不受加入順序的影響。并且兩個線程池是不會互相影響的!
該場景可以用到需要多線程業務當中是沒問題的!!