Search code examples
javamultithreadingconcurrencythreadpooljava.util.concurrent

Java ThreadPool concepts, and issues with controlling the number of actual threads


I am a newbie to Java concurrency and am a bit confused by several concepts and implementation issues here. Hope you guys can help.

Say, I have a list of tasks stored in a thread-safe list wrapper:

ListWrapper jobs = ....

'ListWrapper' has synchronized fetch/push/append functions, and this 'jobs' object will be shared by multiple worker threads.

And I have a worker 'Runnable' to execute the tasks:

public class Worker implements Runnable{
    private ListWrapper jobs;
    public Worker(ListWrapper l){
        this.jobs=l;
    }
    public void run(){
        while(! jobs.isEmpty()){
            //fetch an item from jobs and do sth...
        }
    }
}

Now in the main function I execute the tasks:

int NTHREADS =10;
ExecutorService service= Executors.newFixedThreadPool(NTHREADS);

//run threads..
int x=3;
for(int i=0; i<x; i++){
    service.execute(new Worker(jobs) );
}

I tested this code with 'x=3', and I found that only 3 threads are running at the same time; but as I set 'x=20', I found that only 10 (=NTHREADS) are running at the same time. Seems to me the # of actual threads is the min of the two values.

Now my questions are:

1) Which value ('x' or 'NTHREADS') should I set to control the number of concurrent threads? Or it doesn't matter in either I choose?

2) How is this approach different from simply using the Producer-Consumer pattern --creating a fixed number of 'stud' threads to execute the tasks(shown in the code below)?

Thread t1= new Worker(jobs);
Thread t2= new Worker(jobs);
...
t1.join();
t2.join();
...

Thank you very much!!


Solution

  • You shouldn't create threads by yourself when using a threadpool. Instead of WorkerThread class you should use a class that implements Runnable but is not a thread. Passing a Thread object to the threadpool won't make the thread run actually. The object will be passed to a different internal thread, which will simply execute the run method of your WorkerThread class.

    The ExecutorService is simply incompatible with the way you want to write your program.

    In the code you have right now, these WorkerThreads will stop to work when your ListWrapper is empty. If you then add something to the list, nothing will happen. This is definitely not what you wanted.

    You should get rid of ListWrapper and simply put your tasks directly into the threadpool. The threadpool already incorporates an internal list of jobs shared between the threads. You should just submit your jobs to the threadpool and it will handle them accordingly.

    To answer your questions:

    1) Which value ('x' or 'NTHREADS') should I set to control the number of concurrent threads? Or it doesn't matter in either I choose?

    NTHREADS, the threadpool will create the necessary number of threads.

    2) How is this approach different from simply using the Producer-Consumer pattern --creating a fixed number of 'stud' threads to execute the tasks(shown in the code below)?

    It's just that ExecutorService automates a lot of things for you. You can choose from a lot of different implementations of threadpools and you can substitute them easily. You can use for instance a scheduled executor. You get extra functionality. Why reinvent the wheel?