ThreadPoolExecutor 四種策略

  1. AbortPolicy: 拒絕策略,不指定爲默認值
  2. CallerRunsPolicy: 在任務被拒絕添加後,會調用當前線程池的所在的線程去執行被拒絕的任務
  3. DiscardPolicy: 放棄策略,線程池拒絕的任務直接拋棄,不會拋異常也不會執行
  4. DiscardOldestPolicy: 任務被拒絕添加時,會拋棄任務隊列中最舊的任務也就是最先加入隊列的,再把這個新任務添加進去。

AbortPolicy(拒絕策略)爲默認值

源碼:可以看到直接拋出運行異常

public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

測試代碼:

public class Test {

	public static void main(String[] args) {

		ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 0
				,TimeUnit.MICROSECONDS
				,new ArrayBlockingQueue<>(2,true)
				,new ThreadPoolExecutor.AbortPolicy());  // 拒絕策略

		for (int i = 1; i <= 10; i++) {
			System.out.println("添加第"+i+"個線程");
			executor.execute(new MyThread("線程"+i));
			Iterator iterator = executor.getQueue().iterator();
			if (iterator.hasNext()) {
				while (iterator.hasNext()) {
					MyThread thread = (MyThread) iterator.next();
					System.out.println("隊列queue中:" + thread.name);
				}
			}else {
				System.out.println("隊列中爲null");
			}
		}
	}

	// 內部類 主要是爲線程起名稱方便觀察
	static class MyThread implements Runnable {
		String name;
		public MyThread(String name) {
			this.name = name;
		}
		@Override
		public void run() {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("線程:" + Thread.currentThread().getName() + " 執行:" + name + "  run");
		}
	}
}

運行結果乳如下:

添加第1個線程
隊列中爲null
添加第2個線程
隊列queue中:線程2
添加第3個線程
隊列queue中:線程2
隊列queue中:線程3
添加第4個線程
隊列queue中:線程2
隊列queue中:線程3
添加第5個線程
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task Test$MyThread@593634ad rejected from java.util.concurrent.ThreadPoolExecutor@20fa23c1[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
	at Test.main(Test.java:33)
線程:pool-1-thread-2 執行:線程4  run
線程:pool-1-thread-1 執行:線程1  run
線程:pool-1-thread-1 執行:線程3  run
線程:pool-1-thread-2 執行:線程2  run

分析運行結果:

1.添加第一個任務時,直接執行
  此時隊列中:null
2.添加第二個任務時,由於線程核心數爲"1"並且核心線程被佔用,所以被加入到隊列中
  此時隊列中:任務二
3.添加第三個任務時同上
  此時隊列中:任務二、任務三
4.添加第四個任務時,因爲核心任務還在運行,而且任務隊列已經滿了,所以直接創建新線程執行第四個任務
  此時隊列中:任務二、任務三
5.添加第五個任務時,因爲 maxPoolSize爲2 + 隊列BlockingQueue容量爲2 = 4 也就是最大承載爲4個線程所以執行拒絕策略的rejectedExecution方法,這裏就是執行AbortPolicy的rejectedExecution方法直接拋出異常
6.最終,只有四個線程能完成運行。後面的都被拒絕了。

CallerRunsPolicy

源碼:當發生拒絕是,調用當前線程池的所在的線程去執行被拒絕的任務

public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

        /**
         * Executes task r in the caller's thread, unless the executor
         * has been shut down, in which case the task is discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

測試代碼:其它同上

ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 0
				,TimeUnit.MICROSECONDS
				,new ArrayBlockingQueue<>(2,true)
				,new ThreadPoolExecutor.AbortPolicy());  // 在任務被拒絕添加後,會調用當前線程池的所在的線程去執行被拒絕的任務

運行結果:

添加第1個線程
隊列中爲null
添加第2個線程
隊列queue中:線程2
添加第3個線程
隊列queue中:線程2
隊列queue中:線程3
添加第4個線程
隊列queue中:線程2
隊列queue中:線程3
添加第5個線程
線程:main 執行:線程5  run
隊列queue中:線程2
隊列queue中:線程3
添加第6個線程
線程:pool-1-thread-2 執行:線程4  run
線程:pool-1-thread-1 執行:線程1  run
線程:pool-1-thread-1 執行:線程3  run
線程:main 執行:線程6  run
隊列中爲null
添加第7個線程
線程:pool-1-thread-2 執行:線程2  run
隊列queue中:線程7
添加第8個線程
隊列queue中:線程8
添加第9個線程
隊列queue中:線程8
隊列queue中:線程9
添加第10個線程
隊列queue中:線程8
隊列queue中:線程9
線程:pool-1-thread-2 執行:線程7  run
線程:pool-1-thread-3 執行:線程10  run
線程:pool-1-thread-2 執行:線程8  run
線程:pool-1-thread-3 執行:線程9  run

分析結果:

添加第五個任務,任務5的時候,同樣被線程池拒絕了,因此執行了CallerRunsPolicy的rejectedExecution方法,
這個方法直接執行任務的run方法.因此可以看到任務5是在main線程中執行的
這個策略的缺點就是可能會阻塞主線程。

DiscardPolicy(放棄策略)

源碼:被線程池拒絕的任務直接拋棄,不會拋異常也不會執行。

public static class DiscardPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardPolicy}.
         */
        public DiscardPolicy() { }

        /**
         * Does nothing, which has the effect of discarding task r.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

測試代碼:其它同上

ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 0
				,TimeUnit.MICROSECONDS
				,new ArrayBlockingQueue<>(2,true)
				,new ThreadPoolExecutor.DiscardPolicy());
//線程池拒絕的任務直接拋棄,不會拋異常也不會執行。

運行結果:

添加第1個線程
隊列中爲null
添加第2個線程
隊列queue中:線程2
添加第3個線程
隊列queue中:線程2
隊列queue中:線程3
添加第4個線程
隊列queue中:線程2
隊列queue中:線程3
添加第5個線程
隊列queue中:線程2
隊列queue中:線程3
添加第6個線程
隊列queue中:線程2
隊列queue中:線程3
添加第7個線程
隊列queue中:線程2
隊列queue中:線程3
添加第8個線程
隊列queue中:線程2
隊列queue中:線程3
添加第9個線程
隊列queue中:線程2
隊列queue中:線程3
添加第10個線程
隊列queue中:線程2
隊列queue中:線程3
線程:pool-1-thread-1 執行:線程1  run
線程:pool-1-thread-2 執行:線程4  run
線程:pool-1-thread-1 執行:線程2  run
線程:pool-1-thread-2 執行:線程3  run

分析結果:

只有四個任務被執行了,其他什麼反應都沒有,直接丟棄。

DiscardOldestPolicy(放棄最早策略)

源碼:在rejectedExecution先從任務隊列總彈出最先加入的任務,空出一個位置,然後再次執行execute方法把任務加入隊列。

public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

        /**
         * Obtains and ignores the next task that the executor
         * would otherwise execute, if one is immediately available,
         * and then retries execution of task r, unless the executor
         * is shut down, in which case task r is instead discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

測試代碼:其它同上

ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 0
				,TimeUnit.MICROSECONDS
				,new ArrayBlockingQueue<>(2,true)
				,new ThreadPoolExecutor.DiscardOldestPolicy());

運行結果:

添加第1個線程
隊列中爲null
添加第2個線程
隊列queue中:線程2
添加第3個線程
隊列queue中:線程2
隊列queue中:線程3
添加第4個線程
隊列queue中:線程2
隊列queue中:線程3
添加第5個線程
隊列queue中:線程3
隊列queue中:線程5
添加第6個線程
隊列queue中:線程5
隊列queue中:線程6
添加第7個線程
隊列queue中:線程6
隊列queue中:線程7
添加第8個線程
隊列queue中:線程7
隊列queue中:線程8
添加第9個線程
隊列queue中:線程8
隊列queue中:線程9
添加第10個線程
隊列queue中:線程9
隊列queue中:線程10
線程:pool-1-thread-2 執行:線程4  run
線程:pool-1-thread-1 執行:線程1  run
線程:pool-1-thread-2 執行:線程10  run
線程:pool-1-thread-1 執行:線程9  run

分析結果:

可以看到線程9和線程10頂替了線程2和線程3的位子,其他線程被放棄,既不運行也不拋異常
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章