RejectedExecutionException 分析


當往一個固定隊列ArrayBlockingQueue 不停的提交任務時,會發生什么?

請看如下代碼

 	private static final int QUEUE_SIZE = 20;
	private static final int CORE_POOL_SIZE = 2;
	private static final int MAX_POOL_SIZE = 2;
	private static final int KEEP_ALIVE_TIME = 5;  
  
        public static void main(String[] args) throws Exception {
    	  ThreadPoolExecutor executor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS,
	            new ArrayBlockingQueue<Runnable>(QUEUE_SIZE));
    	  while(true) {
    		SenderTask st = new SenderTask();
    		executor.submit(st);
    	  }
      }

  

run完后會發生如下異常:

Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@b99f7c6 rejected from java.util.concurrent.ThreadPoolExecutor@2959ee1d[Running, pool size = 2, active threads = 2, queued tasks = 20, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372)
at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:110)

 

如果你有研究過executor的源碼你將發現,每次在submit任務的時候,會先進行addWorker()的判斷,如果不能添加成功,則會拋出RejectedExecutionException

 

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps:
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false.
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new
         * thread.  If it fails, we know we are shut down or saturated
         * and so reject the task.
         */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

以上這個異常還有一種出現的情況就是,當你執行完execute.shutdown()后,任然往executor里提交task,也會拋出該異常

示例代碼如下:

	public class RejectedExecutionExceptionExample {

 
    public static void main(String[] args) {

         
        ExecutorService executor = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(15));

         Worker tasks[] = new Worker[20];

        for(int i=0; i<20; i++){

           tasks[i] = new Worker(i);

           executor.execute(tasks[i]);

        }

           executor.shutdown();     

           executor.execute(tasks[0]);//繼續執行任務

    }
}

如何解決呢?

1. 控制提交的任務數量,即提交的任務數量不要超過它當前能處理的能力 (這里可以用生產者消費者的模式來解決)

2. 確保不要在shutdown()之后在執行任務

3. 可以用LinkedBlockingQueue代替ArrayBlockingQueue,因為LinkedBlockingQueue可以設成無界的,但是需要注意,設成無界后最終可能發生OOM(內存溢出),

所以要保證第一二點。

 

參考文獻:https://examples.javacodegeeks.com/core-java/util/concurrent/rejectedexecutionexception/java-util-concurrent-rejectedexecutionexception-how-to-solve-rejectedexecutionexception/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM