天天看點

多線程池newFixedThreadPool之動态多線程池做線程池隔離

背景

     本文不是講述線程池的基本知識,而是在做爬蟲項目實際情況,碰到技術解決方案,簡單的線程隔離的實踐,在做爬蟲時,會碰到反應慢和反應快的各種網站,如何同時用一個線程池去做爬蟲請求,慢的網站會堵塞快的網站請求,這是就考慮線程隔離。線程池基于newFixedThreadPool()建立。

本文部分描述性内容來源于網絡,其中示例性Java源代碼經過本人親自測試,如有不當、錯誤或侵權行為敬請指正。

   基于下圖:

多線程池newFixedThreadPool之動态多線程池做線程池隔離

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的參數指定了可以運作的線程的最大數目,超過這個數目的線程加進去以後,不會立即運作,而是被放入任務隊列中等待執行。其次,加入線程池的線程屬于托管狀态,線程的運作不受加入順序的影響。并且兩個線程池是不會互相影響的!

該場景可以用到需要多線程業務當中是沒問題的!!