【问题标题】:How to check if the threads have completed its task or not?如何检查线程是否完成了任务?
【发布时间】:2015-03-04 13:34:14
【问题描述】:

好的,我创建了几个线程来完成一些复杂的任务。现在如何检查每个线程是否成功完成??

class BrokenTasks extends Thread {
     public BrokenTasks(){
       super();
     }
    public void run(){
     //Some complex tasks related to Networking..
     //Example would be fetching some data from the internet and it is not known when can it be finished
      }
      }


    //In another class 
    BrokenTasks task1 = new BrokenTasks();
    BrokenTasks task2 = new BrokenTasks();
    BrokenTasks task3 = new BrokenTasks();
    BrokenTasks task4 = new BrokenTasks();
    task1.start();
    .....
    task4.start();

那么我如何检查这些所有任务是否成功完成 i) 主程序(主线程) ii) 从每个连续的线程中。例如:检查 task1 是否已经从 task2 中结束..

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    使用线程的一个好方法是不直接使用它们。而是创建一个线程池。然后在您的 POJO 任务封装中有一个仅在计算结束时设置的字段。

    当另一个线程可以看到状态时,可能会有 3-4 毫秒的延迟 - 但最终 JVM 做到了。只要其他线程不过度写入它。您可以通过确保每个任务都有一个唯一的工作实例和状态来保护这一点,而其他线程仅每 1-5 秒轮询一次,或者有一个工作人员在完成后调用的侦听器。 我用过的图书馆是我自己的 https://github.com/tgkprog/ddt/tree/master/DdtUtils/src/main/java/org/s2n/ddt/util/threads

    要使用:在服务器启动或静态块中:

    package org.s2n.ddt.util;
    
    import org.apache.log4j.Logger;
    import org.junit.Test;
    
    import org.s2n.ddt.util.threads.PoolOptions;
    import org.s2n.ddt.util.threads.DdtPools;
    
    public class PoolTest {
        private static final Logger logger = Logger.getLogger(PoolTest.class);
    
        @Test
        public void test() {
            PoolOptions options = new PoolOptions();
            options.setCoreThreads(2);
            options.setMaxThreads(33);
            DdtPools.initPool("a", options);
            Do1 p = null;
            for (int i = 0; i < 10; i++) {
                p = new Do1();
                DdtPools.offer("a", p);
    
            }
            LangUtils.sleep(3 + (int) (Math.random() * 3));
            org.junit.Assert.assertNotNull(p);
            org.junit.Assert.assertEquals(Do1.getLs(), 10);
        }
    
    }
    
    class Do1 implements Runnable {
        volatile static long l = 0;
    
        public Do1() {
            l++;
    
        }
    
        public void run() {
    
            // LangUtils.sleep(1 + (int) (Math.random() * 3));
            System.out.println("hi " + l);
        }
    
        public static long getLs() {
            return l;
        }
    }
    

    你不应该做的事情: * 不要每 10-15 毫秒做一次事情 * 除非学术不做自己的线程 * 不要让它比 97% 的情况更复杂

    【讨论】:

    • 你能详细说明你的答案吗?就像添加使用线程池的示例代码...
    • 更新的答案将注意到应用代码没有新线程。
    【解决方案2】:

    您可以使用CallableForkJoinPool 执行此任务。

    class BrokenTasks implements Callable {
        public BrokenTasks(){
           super();
        }
        public Object call() thrown Exception {
         //Some complex tasks related to Networking..
         //Example would be fetching some data from the internet and it is not known when can it be finished
        }
    }
    
    
    //In another class 
    BrokenTasks task1 = new BrokenTasks();
    BrokenTasks task2 = new BrokenTasks();
    BrokenTasks task3 = new BrokenTasks();
    BrokenTasks task4 = new BrokenTasks();
    
    ForkJoinPool pool = new ForkJoinPool(4);
    Future result1 = pool.submit(task1);
    Future result2 = pool.submit(task2);
    Future result3 = pool.submit(task3);
    Future result4 = pool.submit(task4);
    
    value4 = result4.get();//blocking call
    value3 = result3.get();//blocking call
    value2 = result2.get();//blocking call
    value1 = result1.get();//blocking call
    

    然后不要忘记关闭池。

    【讨论】:

      【解决方案3】:

      您可以使用Thread.isAlive 方法,请参阅API:“如果线程已启动且尚未死亡,则线程处于活动状态”。那就是在 task2 run() 你测试 task1.isAlive()

      要从 task2 中查看 task1,您需要将其作为参数传递给 task2 的构造函数,或者创建任务字段而不是本地变量

      【讨论】:

        【解决方案4】:

        通常,您只需加入要完成的线程即可。在加入完成之前,您的线程不会继续。例如:

        // await all threads
        task1.join();
        task2.join();
        task3.join();
        task4.join();
        // continue with main thread logic
        

        (我可能会将任务放在一个列表中以便更清洁地处理)

        【讨论】:

          【解决方案5】:

          如果一个线程还没有完成它的任务,那么它仍然是活着的。所以为了测试线程是否已经完成了它的任务,你可以使用isAlive()方法。

          【讨论】:

            【解决方案6】:

            这里有两个不同的问题

            一个是线程是否仍在工作。
            另一个是如果任务还没有完成。

            线程是一种非常昂贵的解决问题的方法,当我们在java中启动一个线程时,VM必须存储上下文信息并解决同步问题(例如锁)。所以我们通常使用线程池而不是直接使用线程。线程池的好处是我们可以使用很少的线程来处理许多不同的任务。这意味着很少有线程保持活动状态,而许多任务已经完成。

            不要从线程中找到任务状态。

            线程是工作者,任务是作业。
            一个线程可以一个一个地处理许多不同的工作。
            我认为我们不应该问工人是否完成了工作。我宁愿问工作是否完成。

            当我想检查作业是否完成时,我使用信号。

            使用信号(同步辅助)

            自从 JDK 1.5 起,有许多同步辅助工具就像一个信号一样工作。

            CountDownLatch

            这个对象提供了一个计数器(只能设置一次,倒计时多次)。此计数器允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。

            CyclicBarrier

            这是另一个有用的信号,它允许一组线程互相等待以达到共同的障碍点。

            更多工具

            更多工具可以在 JDK java.util.concurrent 包中找到。

            【讨论】:

            • 我认为这已经结束了。如果您已将作业分配给线程/池,并且已隔离该任务,则可以添加一个属性进行检查。
            • @tgkprog 一个属性是一个属于一个对象的变量,如果你的意思是一个属性被添加到一个任务中,我同意这是可以的。我说的重点是我们不应该使用线程中的属性。
            【解决方案7】:
            You can use the following..
            task1.join();
            task2.join();
            task3.join();
            task4.join();
            // and then check every thread by using isAlive() method
            e.g : task1.isAlive(); 
            if it return false means that thread had completed it's task
            otherwise it will true
            

            【讨论】:

            • isAlive() 这里似乎没有必要;根据定义,线程已终止,以便 join() 返回。
            • 我知道,但是如果你想检查线程是否正在运行,那么将使用 isAlive()
            【解决方案8】:

            我不确定您的确切需求,但一些 Java 应用程序框架具有方便的抽象来处理单个工作单元或“作业”。 Eclipse 富客户端平台以其 Jobs API 浮现在脑海中。虽然这可能有点矫枉过正。

            对于普通的旧 Java,请查看 Future、Callable 和 Executor。

            【讨论】:

              猜你喜欢
              • 2018-04-18
              • 1970-01-01
              • 2011-02-15
              • 1970-01-01
              • 1970-01-01
              • 2016-12-20
              • 2011-01-30
              • 2021-04-13
              • 1970-01-01
              相关资源
              最近更新 更多