9

I'm trying to understand the behavior of queues in ThreadPoolExecutor. In the below program, when I use LinkedBlockingQueue, I can submit only one task to the thread pool at a time. But if I replace the LinkedBlockingQueue with SynchronousQueue, I could submit all the 5 tasks to the pool at an instant. How SynchronousQueue differs from LinkedBlockingQueue in this case ?

Java program :

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Sample {
    public static void main(String[] args) throws InterruptedException {
        LinkedBlockingQueue<Runnable> threadPoolQueue = new LinkedBlockingQueue<>();
//      SynchronousQueue<Runnable> threadPoolQueue = new SynchronousQueue<>();
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        ThreadPoolExecutor tpe = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, threadPoolQueue, threadFactory);
        Runnable np;

        for (int i = 1; i <= 5; i++) {
            np = new SampleWorker("ThreadPoolWorker " + i);
            tpe.submit(np);
        }

        System.out.println(tpe.getCorePoolSize());
        System.out.println(tpe.getPoolSize());
        System.out.println(tpe.getActiveCount());

        tpe.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
        tpe.shutdown();
        System.out.println("Main task finished");
    }
}

class SampleWorker implements Runnable {
    private String workerName;

    SampleWorker(String tName) {
        workerName = tName;
    }

    @Override
    public void run() {
        try {
            for (int i = 1; i <= 10; i++) {
                Thread.sleep(3000);
                System.out.println(this.workerName);
            }
            System.out.println(this.workerName + " finished");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
xingbin
  • 27,410
  • 9
  • 53
  • 103
UnahD
  • 867
  • 2
  • 10
  • 25
  • 1
    Take look at [this](https://stackoverflow.com/questions/8591610/when-should-i-use-synchronousqueue) – Dawid Fieluba Dec 05 '17 at 09:42
  • @avix That explains the difference between `SynchronousQueue` and `LinkedBlockingQueue` (with a size of 1). But here I'm didn't specify any size for either of the queues. And with the `LinkedBlockingQueue` I could submit only one task at a time, whereas with the `SynchronousQueue` I could submit all the 5 tasks simultaneously. I have set to `corePoolSize` to 0 in both the cases. Will `corePoolSize` doesn't affect `SynchronousQueue` ? – UnahD Dec 05 '17 at 09:51
  • @UnahD `corePoolSize` doesn't affect underlying `BlockingQueue`, it controls thread pool size of `ThreadPoolExecutor`, not `BlockingQueue` size. And, as documentation says, `SynchronousQueue` [does not have any internal capacity, not even a capacity of one](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/SynchronousQueue.html) and also `size()` [always returns zero](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/SynchronousQueue.html#size()) – Maxim Ponomarev Dec 05 '17 at 10:11

1 Answers1

18

When you submit a task to ThreadPoolExecutor, it works like this :

if (numberOfWorkingThreads < corePoolSize) {
   startNewThreadAndRunTask();
} else if (workQueue.offer(task)) {
   if (numberOfWorkingThreads == 0) {
       startNewThreadAndRunTask();
   }
} else if (numberOfWorkingThreads < maxPoolSize)
    startNewThreadAndRunTask();
} else {
    rejectTask();
}
  • When using LinkedBlockingQueue with no initial value, workQueue.offer(task) will always success, resulting only one thread started.
  • When calling SynchronousQueue.offer(task), it successes only when another thread is waiting to receive it. Since there is no waiting thread, false will be returned and new thread is created every time.
xingbin
  • 27,410
  • 9
  • 53
  • 103