我在下面一段导致线程永不终止的代码中做错了什么?

时间:2016-02-01 01:27:44

标签: java multithreading

我有以下代码,我希望最后打印“DONE”。但是当我跑步时,“DONE”从未被打印过,而JVM实际上从未终止过。

我做错了什么?

// File: Simple.java
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Simple {


    public static void main(String[] args) throws Exception{

        doTest(3);

    }

    private static void doTest(final int times) {

        ScheduledExecutorService tp = Executors.newScheduledThreadPool(times);

         Thread[] runnables = new Thread[times];
         for (int i = 0; i < runnables.length; ++i) {
             runnables[i] = new Thread(new MyRunnable());
         }

         // schedule for them all to run
         for (Thread t : runnables) {
             tp.schedule(t, 1, TimeUnit.SECONDS);
         }


         try {
            tp.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
            System.out.println("DONE!");
         }catch (InterruptedException e) {
            e.printStackTrace();
        }

     }


    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("hello world");
        }

    }

}

3 个答案:

答案 0 :(得分:2)

这里有两件事你做错了。

首先,如果您使用的是ExecutorService,那么您也不应该创建自己的线程。只需将Runnables直接提交给执行程序 - 执行程序服务就有自己的线程集合,并运行您在自己的线程上提交的任何内容,因此您创建的线程甚至无法启动。

其次,如果你已经完成了ExecutorService,并且要等到它终止,你需要在提交上一份工作后在执行者服务上调用shutdown()

答案 1 :(得分:0)

您忘了shutdown ExecutorService

tp.shutdown(); // <-- add this
tp.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);

另外我应该提一下,创建Thread以将它们用作Runnable s不仅毫无意义,而且可能会产生误导。对于Runnable变量,您应该使用Thread而不是runnables

Runnable[] runnables = new Runnable[times];

答案 2 :(得分:0)

Executors.newScheduledThreadPool(times)对其ThreadFactory使用Executors.defaultThreadFactory()。

Here is the documentation

  

当Java虚拟机启动时,通常只有一个   非守护程序线程(通常调用名为main的方法)   指定班级)。 Java虚拟机继续执行   线程,直到发生以下任一情况:

     
      
  • 已调用类Runtime的exit方法,安全管理器已允许退出操作。
  •   
  • 所有非守护程序线程的线程都已死亡,无论是通过调用run方法返回还是抛出异常   传播超出run方法。
  •   

所以,这就是你所拥有的;但我改变了3件事。

  • 添加了关机挂钩
  • 使每个时间表延迟一个额外的时间来演示即使在调度程序调用某些线程之前调用了关闭。
  • 最后,你告诉它要永远等待使用Long.MAX。但我认为你这样做是因为关机感觉它现在会关闭。但事实并非如此。

    public static void main(String[] args) throws Exception {
    
        doTest(3);
    
    }
    
    private static void doTest(final int times) {
    
        ScheduledExecutorService tp = Executors.newScheduledThreadPool(times);
    
        Thread[] runnables = new Thread[times];
        for (int i = 0; i < runnables.length; ++i) {
            runnables[i] = new Thread(new MyRunnable());
        }
    
        // schedule for them all to run
        int i = 1;
        for (Thread t : runnables) {
            tp.schedule(t, i++, TimeUnit.SECONDS);
        }
    
    
        System.out.println("Calling shutdown");
        tp.shutdown();
    }
    
    
    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("hello world");
    
        }
    
    }
    

希望能回答你的问题。现在,你有点复制东西。

如果你打算使用executerservice,你应该告诉它为你安排一些事情。

public static void main(String[] args) throws Exception {

    doTest(3);

}

private static void doTest(final int times) {

    ScheduledExecutorService tp = Executors.newScheduledThreadPool(times);

    for (int i = 0; i < times; ++i) {
        tp.schedule(new MyRunnable(), 1, TimeUnit.SECONDS);
    }



    System.out.println("Calling shutdown");
    tp.shutdown();
}


static class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("hello world");

    }

}