问题
I have a method called action() that deploys three threads. Each deployed thread or worker thread falls into a while loop based on a single instance variable of type boolean being true, for example boolean doWork = true, each thread will have a while(doWork){} loop.
When a thread finishes the job will set the doWork to false stopping all the threads from looping. Then I would like to be able to somehow let the main thread recall the action() method to redeploy the threads to do another job. (If I use one of the worker threads to call the action() method is it OK ?) will the worker thread terminate once it calls the action() method and somehow die ?
I limited the example to two threads for simplicity
Thanks
class TestThreads{
boolean doWork = true;
void action(){
ThreadOne t1 = new ThreadOne();
ThreadTwo t2 = new ThreadTwo();
}
//innerclasses
class ThreadOne implements Runnable{
Thread trd1;
public ThreadOne(){//constructor
if(trd1 == null){
trd1 = new Thread(this);
trd1.start();
}
}
@Override
public void run(){
while(doWork){
//random condition
//would set doWork = false;
//stop all other threads
}
action();//is the method in the main class
}
}
class ThreadTwo implements Runnable{
Thread trd2;
public ThreadTwo(){//constroctor
if(trd2 == null){
trd2 = new Thread(this);
trd2.start();
}
}
@Override
public void run(){
while(doWork){
//random condition
//would set doWork = false;
//stop all other threads
}
action();//is the method in the main class
}
}
}
回答1:
How about this implementation:
Declare a class member doWork
, a counter for currently active threads and a synchronization object:
private volatile boolean doWork = true;
private AtomicInteger activeThreads;
private Object locker = new Object();
In main:
while(true) {
// call action to start N threads
activeThreads = new AtomicInteger(N);
action(N);
// barrier to wait for threads to finish
synchronized(locker) {
while(activeThreads.get() > 0) {
locker.wait();
}
}
}
In thread body:
public void run() {
while(doWork) {
...
// if task finished set doWork to false
}
// signal main thread that I've finished
synchronized(locker) {
activeThreads.getAndDecrement();
locker.notify();
}
}
回答2:
Skeleton code
// OP said 3 threads...
ExecutorService xs = Executors.newFixedThreadPool(3);
...
// repeat the following as many times as you want...
// this is the setup for his 3 threads - as Callables.
ArrayList<Callable<T>> my3Callables = new ArrayList<Callable<T>>();
my3Callables.add(callable1);
my3Callables.add(callable2);
my3Callables.add(callable3);
try {
List<Future<T>> futures = xs.invokeAll(my3Callables );
// below code may not be needed but is useful for catching any exceptions
for (Future<T> future : futures) {
T t = future.get();
// do something with T if wanted
}
}
catch (ExecutionException ee) {
// do something
}
catch (CancellationException ce) {
// do something
}
catch (InterruptedException ie) {
// do something
}
回答3:
I'll expand my comment (even though @babernathy as added this to his answer).
Typically where you have a pool of threads where you want to execute some piece of work, and you have a main thread managing the items of work that you want done, the ExecutorService
provides the ideal framework.
In your main object, you can create an instance of the service (with the number of threads you want), and then as you generate a piece of work, submit it to the service, and the service will pick the next available thread from the pool and execute it.
If you have a dependency on knowing if particular pieces of work have completed, you can use something like a CountDownLatch
to track when threads have completed their work. My point, there are quite a few existing frameworks for this kind of activity, no need to go through the pain all over again...
回答4:
It's a little difficult to give you an exact solution without any code. It sounds like you are describing the producer/consumer pattern where you give a set of worker threads some tasks and when they are done, you give them more.
Here is a web page that does an OK job of describing what to do.
Also take a look at the ExecutorService that allows you to submit Runnables and have them executed.
回答5:
A simple solution is to have the main thread sleep:
static boolean doWork = true; // better to use AtomicBoolean
void action() {
// start workers, which eventually set doWork = false
while (doWork) {
Thread.sleep(/**time in millis**/); // main thread waits for workers
}
// logic to run action() again, etc.
}
The main thread starts the workers, periodically waking up to check if they've terminated. Since the main thread is an "arbiter", it probably shouldn't die just to be resurrected by one of its children.
Reference
- Thread.sleep()
- AtomicBoolean
来源:https://stackoverflow.com/questions/9100515/is-it-possible-to-call-the-main-thread-from-a-worker-thread-in-java