2

When I try to learn about Java threads, I usually come across with the code examples with wait() and notify() in the very same class (infact nearly all of them producer-consumer examples). After googling various examples, unfortunately I could not find the the case I need which is:

  • A manager thread initially creates n number of threads (and starts them) in which a http get request is done in a sigle thread.
  • For a single worker thread it takes about 20-30 seconds to complete its life.
  • Here my manager thread must know which of workers have finished, and replaces finishing thread with a new one.

I thought about an approach like that (let n be 5):

List<Runnable> runnables = new ArrayList<Runnable>();
for(int i = 0 ; i < 5 ; i++){
    runnables.add(new MyWorker(params));
}
for(Runnable myWorker : runnables){
   myWorker.run();
}

Since wait() does not support multiple objects I cannot keep on going from here. Another solution can be implementing busy wait on manager thread that is calling some isFinished flag for each worker. But I'm not sure either this a good approach (as far as I know this is resource wasting)

5
  • 4
    You are probably looking for a ThreadPoolExecutor. See also utility class Executors, which has static factory methods for the most common scenarios. Commented Jan 1, 2013 at 21:56
  • @fge: you should post that as an answer (and elaborate a bit more). Commented Jan 1, 2013 at 22:09
  • 1
    I would not bother with wait and notify which can be tricky to use. There are high level threading facilities in the java.util.concurrent package that are much easier to use. Commented Jan 1, 2013 at 22:12
  • @JBNizet done, please fix any mistakes ;) Commented Jan 1, 2013 at 22:52
  • Do you want to force sequential execution of each thread? In your code above, you aren't actually starting new threads, you are simply calling the run method of each Thread object. No multithreading occuring! Really depends what you want to do. Commented Jan 2, 2013 at 0:13

2 Answers 2

3

There is a ready-to-use tool in Java 6 and above, in the form of the executor framework.

Since you want to have a fixed pool of threads, your best bet is to use:

ExecutorService service = Executors.newFixedThreadPool(5);

You can then submit your Runnable instances using the .execute() method (which is defined by the Executor interface). They will be submitted to a work queue and dequeued as soon as a thread in the pool is available.

If your individual thread-working methods return a value (ie, they implement Callable<Something>), then you can use the .submit() method (defined by ExecutorService, also an interface which extends Executor), which will return a Future<Something> from which you will .get() the computed values.

Terminating a thread pool is done in various ways: .shutdown() is the most basic and will synchronously wait for still active threads to terminate (and prevent new jobs to be submitted).

Javadocs: Executors, ExecutorService, ThreadPoolExecutor.

Other link: a book you should buy for all things thread-related (does not cover Java 7's ForkJoinPool however).

PS: how lucky, the sample chapter of the book above (PDF) covers task execution ;)

Sign up to request clarification or add additional context in comments.

2 Comments

This Executor framework looks what I want, now I'm reading how can I assign workers, after finishing ones. Some blocking queue examples are out there. Besides my workers do not return anything they just do file i/o
@px5x2: well, just use .execute() in this case. As to thread handling, it is done automatically, you need not worry about it at all -- which is the nice thing ;) You can of course implement your own ThreadPoolExecutor, but you would have to have very specific needs.
1

You can use semaphore and wait/notify approach to accomplish what you are trying to do. The approach is:

  1. Initialize the semaphore with maximum number of threads allowed at once.
  2. Wait until task is available in queue.
  3. Acquire a semaphore.
  4. Run the task and on finish release the semaphore.

Put all the four steps in forever while loop and you are ready with your task executer. This is only for learning purpose, as @fge said there already exists ThreadPoolExecuter which can do the same thing for you and is more optimized.

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Semaphore;

public class ThreadExecuter extends Thread {

    Queue<Runnable> tasks = new LinkedList<Runnable>();
    Semaphore s;
    Object bin = new Object();

    public ThreadExecuter(int n) {
        s = new Semaphore(n);
    }

    public void addTask(Runnable r) {
        synchronized (bin) {
            tasks.add(r);
            bin.notifyAll();
        }
    }

    public void run() {
        while (true) {
            try {
                final Runnable r;
                synchronized (bin) {
                    while (tasks.isEmpty())
                        bin.wait();
                    r = tasks.poll();
                }

                s.acquire();
                new Thread() {
                    public void run() {
                        r.run();
                        s.release();
                    }
                }.start();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }
}

The main method looks like this:

import java.util.Random;

public class ThreadTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
            /* to make maximum 10 threads each running 1 runnable */
        ThreadExecuter executer = new ThreadExecuter(10);
        executer.start();

        for(int i = 0; i < 5000; i++) {
                    /* add task in executer, this is non blocking */
            executer.addTask(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Task Executed in " 
                                        + Thread.currentThread().getId());
                    try {
                        Thread.sleep(new Random().nextInt(8000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.