ThreadPoolExecutor Block When Queue Is Full?

前端 未结 8 1843
无人及你
无人及你 2020-11-29 17:42

I am trying to execute lots of tasks using a ThreadPoolExecutor. Below is a hypothetical example:

def workQueue = new ArrayBlockingQueue(3, f         


        
8条回答
  •  余生分开走
    2020-11-29 18:15

    You could use a semaphore to block threads from going into the pool.

    ExecutorService service = new ThreadPoolExecutor(
        3, 
        3, 
        1, 
        TimeUnit.HOURS, 
        new ArrayBlockingQueue<>(6, false)
    );
    
    Semaphore lock = new Semaphore(6); // equal to queue capacity
    
    for (int i = 0; i < 100000; i++ ) {
        try {
            lock.acquire();
            service.submit(() -> {
                try {
                  task.run();
                } finally {
                  lock.release();
                }
            });
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    

    Some gotchas:

    • Only use this pattern with a fixed thread pool. The queue is unlikely to be full often, thus new threads won't be created. Check out the java docs on ThreadPoolExecutor for more details: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html There is a way around this, but it is out of scope of this answer.
    • Queue size should be higher than the number of core threads. If we were to make the queue size 3, what would end up happening is:

      • T0: all three threads are doing work, the queue is empty, no permits are available.
      • T1: Thread 1 finishes, releases a permit.
      • T2: Thread 1 polls the queue for new work, finds none, and waits.
      • T3: Main thread submits work into the pool, thread 1 starts work.

      The example above translates to thread the main thread blocking thread 1. It may seem like a small period, but now multiply the frequency by days and months. All of a sudden, short periods of time add up to a large amount of time wasted.

提交回复
热议问题