【问题标题】:Is it possible to call the main thread from a worker thread in Java?是否可以从 Java 中的工作线程调用主线程?
【发布时间】:2012-02-01 17:38:34
【问题描述】:

我有一个名为 action() 的方法,它部署了三个线程。每个部署的线程或工作线程都基于布尔类型的单个实例变量为 true 进入一个 while 循环,例如 boolean doWork = true,每个线程将有一个 while(doWork){} 循环。

当一个线程完成作业时,会将 doWork 设置为 false 以阻止所有线程循环。然后我希望能够以某种方式让主线程调用 action() 方法来重新部署线程来完成另一项工作。 (如果我使用其中一个工作线程调用 action() 方法可以吗?)一旦工作线程调用 action() 方法并以某种方式死亡,工作线程会终止吗?

为了简单起见,我将示例限制为两个线程

谢谢

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
          }
    }

}

【问题讨论】:

  • 为什么不使用 ExecutorService 它专为您正在做的事情而设计?
  • 尽管我已经对@Nim 评论投了赞成票,但让我重复一遍:看看 ExecutorService 是否有这种事情。
  • @Nim 如果您写一个包含更多细节的答案可能会更好,因为它可能会引起其他人的兴趣
  • @AdelBoutros 我在下面的答案中加入了一些合理的骨架代码。

标签: java multithreading worker-thread


【解决方案1】:

这个实现怎么样:

声明一个类成员doWork,一个当前活动线程的计数器和一个同步对象:

private volatile boolean doWork = true;
private AtomicInteger activeThreads;
private Object locker = new Object();

主要:

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();
       }
    }
}

在线程体中:

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】:

    骨架代码

    // 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】:

      我会扩展我的评论(尽管@babernathy 已将此添加到他的回答中)。

      通常你有一个线程池你想要执行一些工作,你有一个主线程来管理你想要完成的工作项,ExecutorService 提供理想的框架。

      在您的主对象中,您可以创建一个服务实例(具有您想要的线程数),然后当您生成一个工作时,将其提交给服务,服务将选择下一个可用的线程池中的线程并执行它。

      如果您依赖于了解特定工作是否已完成,您可以使用CountDownLatch 之类的东西来跟踪线程何时完成工作。我的意思是,这种活动已有相当多的框架,无需再经历痛苦......

      【讨论】:

        【解决方案4】:

        在没有任何代码的情况下给你一个精确的解决方案有点困难。听起来你在描述生产者/消费者模式,你给一组工作线程一些任务,当它们完成后,你给它们更多。

        这是一个web page,它可以很好地描述要做什么。

        还可以查看ExecutorService,它允许您提交 Runnables 并执行它们。

        【讨论】:

          【解决方案5】:

          一个简单的解决方案是让主线程休眠:

          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.
          
          }
          

          主线程启动worker,定期唤醒以检查它们是否已终止。由于主线程是一个“仲裁者”,它可能不应该仅仅为了被它的一个孩子复活而死。

          参考

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-11-30
            • 1970-01-01
            • 1970-01-01
            • 2021-01-05
            • 2013-03-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多