优雅地结束基于控制台的多线程程序

时间:2018-04-20 22:49:00

标签: java multithreading

我有以下课程,我通常会运行大约10个帖子

public class MyClass implements Runnable {    
  private volatile Device device = null;

  public MyClass(Device device) {
    this.device = device;
  }

  @Override
  public void run() {
    while (true) {  // <--- I do know that the "true" has to be changed to a Boolean
      try {
        Worker worker = new Worker();
        worker.work();
        System.out.println("Waiting 6 seconds!");
        Thread.sleep(6 * 1000);
        System.out.println("------------------------------------");
      } catch (Exception e) {
        e.printStackTrace();
      }
    }

    System.out.println("Thread in program ended!");
  }
}

在我的主要内容中我开始像这样的线程

for (int i = 0; i < 2; i++) {
  (new Thread(new MyClass())).start();
}

这是一个基于控制台的程序。结束该计划最可靠的方法是什么?我认为最好的方法是将while (true)更改为while (Boolean)并以某种方式更改所有线程的布尔值,然后当循环结束时,程序将正常结束。

3 个答案:

答案 0 :(得分:0)

这里我通过等待用户输入结束它,但你可以改变它以从任何地方触发停止方法

    public static void main(String[] args) {

    List<MyClass> myThreads = new ArrayList<>();
    for (int i = 0; i < 2; i++) {
        MyClass myClass = new MyClass();
        Thread t = new Thread(myClass);
        t.start();
        myThreads.add(myClass);
    }
    Scanner in = new Scanner(System.in);
    in.next();

    for(MyClass t : myThreads){
        t.stop();
    }

}

class MyClass implements Runnable {

private Boolean flag;

public MyClass() {
    this.flag = true;
}

@Override
public void run() {
    while (flag) {  // <--- I do know that the "true" has to be changed to a Boolean
        try {
            System.out.println("Waiting 6 seconds!");
            Thread.sleep(6 * 1000);
            System.out.println("------------------------------------");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    System.out.println("Thread in program ended!");
}

public void stop(){
    this.flag = false;
} }

答案 1 :(得分:0)

简单的方法是将所有线程存储在一个集合中,并在最后将make循环连接起来 请注意,这不是最正常的方法,也不是最有效的方法。

在您的主页:

HashSet<Thread> threads = new HashSet();

for (int i = 0; i < 2; i++) {
    Thread t = new Thread(new MyClass());
    threads.add(t);
    t.start();
}

for (Thread thread: threads) {
    thread.join();
}

some more material

答案 2 :(得分:0)

以下代码使用执行程序服务来修复任何时候运行的线程数,它提供了一个Future对象,它还可以告诉您线程何时正常关闭。它们也共享一个关闭对象。这为您提供了更多的灵活性,因为执行程序服务可以让您在任何时候优雅地决定运行多少个线程。

首先,我们创建了一个共享关闭对象,它将通知所有线程关闭的时间。将有一个这样的实例,每个线程都有一个副本。

    public static class Shutdown {
        private boolean running;

        public void shutdown() {
            this.running = false;
        }

        public boolean isRunning() {
            return running;
        }
    }

接下来让我创建一个虚拟线程,它只会在运行时永远休眠。显然你可以用你自己的线程替换它来做一些有用的事情。

    public static class MyClass implements Runnable {
        final Shutdown shutdown;


        public MyClass(Shutdown shutdown) {
            this.shutdown = shutdown;
        }

        @Override
        public void run() {
            while (shutdown.isRunning()) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    System.out.println("Did not gracefully shut down");
                }
            }

            System.out.println("Thread in program ended!");
        }
    }
}

现在,对于将运行一切的主类,这就是魔术发生的地方。

public class Main {
    public static void main(String[] args) {

        //run exactly 10 threads at a time
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        //this is how we shut it down
        Shutdown globalShutdown = new Shutdown();

        //start up the 10 threads
        List<Future<?>> futures = new ArrayList<>();
        for(int i = 0; i< 10; i++)
            futures.add(executorService.submit(new MyClass(globalShutdown)));

        //gracefully shut them down
        globalShutdown.shutdown();

        try {
            //wait for them all to shutdown
            for(Future<?> future : futures)
                future.get();
        } catch (InterruptedException e) {
            throw new IllegalStateException("This should never happen");
        } catch (ExecutionException e) {
            throw new IllegalStateException("This should never happen");
        }

        //everything got shutdown!
    }

在实践中,您可能还想处理由于错误而导致线程无法正常结束的情况。您可能希望添加超时而不是永久停止,如果超过该超时,则只需强制终止所有剩余的线程。为此,用这个替换上面的try-catch块。

    try {
        //wait for them all to shutdown
        boolean timedout = false;
        for(Future<?> future : futures) {
            if( !timedout ) {
                try {
                    future.get(30, TimeUnit.SECONDS);
                } catch (TimeoutException e) {
                    timedout = true;
                }
            }

            if(timedout) {
                future.cancel(true);
            }
        }
    } catch (InterruptedException | ExecutionException e) {
        throw new IllegalStateException("This should never happen");
    }