blauerschluessel
blauerschluessel

Reputation: 229

How does the ExecutorService(int n) and Thread.activeCount() work?

I have the following Code Snippet:

int k = 4;

        ExecutorService e = Executors.newFixedThreadPool(k);
        for (int i = 1; i <= k; i++) {
            e.execute(new C(i));
            e.execute(new C(i));
        }
        int active = Thread.activeCount();
        System.out.println(active);
        e.shutdown();

Clearly visible I submit two C per iteration through the loop. In my case 8 C are submitted, even though the ExecutorService has fixed size of 4. This is also confirmed by counting the active Threads which is 5.

Is this behaviour intended? I don't understand why seemingly just 4 new threads are started and counted, eventhough 8 are submitted. I would be very happy, if someone could clear up the concept of the ExecutorService and Thread.activeCount() for me.

Upvotes: 0

Views: 2805

Answers (2)

Ravindra babu
Ravindra babu

Reputation: 38910

I don't understand why seemingly just 4 new threads are started and counted, eventhough 8 are submitted.

Don't confuse between Threads and tasks. You have created a fixed ThreadPool for 4 threads and only 4 threads will remain in the pool.

Check implementation of Executors

 /**
     * Creates a thread pool that reuses a fixed number of threads
     * operating off a shared unbounded queue.  At any point, at most
     * <tt>nThreads</tt> threads will be active processing tasks.
     * If additional tasks are submitted when all threads are active,
     * they will wait in the queue until a thread is available.
     * If any thread terminates due to a failure during execution
     * prior to shutdown, a new one will take its place if needed to
     * execute subsequent tasks.  The threads in the pool will exist
     * until it is explicitly {@link ExecutorService#shutdown shutdown}.
     *
     * @param nThreads the number of threads in the pool
     * @return the newly created thread pool
     * @throws IllegalArgumentException if <tt>nThreads &lt;= 0</tt>
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

You can find more details about individual parameters of ThreadPoolExecutor at official documentation page.

In your case, number of threads are 4. Number of worker tasks ( which are implementing Runnable interface) are 8.

How are they stored, how can they be accessed? Is it also possible to manipulate them midway, maybe why other calls arrive?

  1. Tasks are submitted to task queue ( BlockingQueue)
  2. If BlockingQueue is full ( bounded queue), Rejection Policy will be triggered.
  3. If BlockingQueue is not full, worker tasks will wait for Thread to pick-up them.

Related SE posts:

How to properly use Java Executor?

Task getting rejected although threads are available

Upvotes: 1

Rob
Rob

Reputation: 6487

A primary goal of the ExecutorService you have created is a fixed-size thread pool (in your case four threads). If you are seeing just four Thread instances created for your eight pieces of work, then it is working as designed.

You seem to think there should have been eight threads created. Imagine if you had submitted one million pieces of work; it would be a disaster if one million threads were created.

The abstraction allows you to control how many threads are used at one time, without regard to how many items there are to process. The ExecutorService deals with the complexity of reusing the four threads as many times as needed to process all of the items you pass to calls to execute.

An analogy that might explain this is a bank. You created a bank with four tellers (the four threads in the thread pool) and eight customers (the eight calls to execute) in line. When a teller finishes with a customer, the next customer in line gets serviced by that teller. You add someone to the queue with a call to execute and the ExecutorService manages everything else. You control the number of threads (tellers) by how you initialize the ExecutorService (there are many different flavors that you can create).

Upvotes: 4

Related Questions