运行while语句后结束Java线程

时间:2015-01-23 13:18:47

标签: java multithreading

我的程序完成后,我遇到了一个结束线程的问题。我运行一个线程时钟对象,它工作得很好,但我需要结束所有线程,当时间'=='一小时这一点似乎工作我只需要知道如何结束它们。下面是我所拥有的代码示例,除了在此代码上面定义的一个int之外,这是run方法中唯一运行的东西。

    @Override
    public void run()
    {
        int mins = 5;
        while(clock.getHour() != 1)
        {
            EnterCarPark();
            if(clock.getMin() >= mins)
            {
                System.out.println("Time: " + clock.getTime() + " " + entryPoint.getRoadName() + ": " + spaces.availablePermits() + " Spaces");
                mins += 5;
            }
        }
    }

但是当你继续观察在netbeans的调试模式下运行的线程时,它们会在一小时后继续运行,但不确定如何解决这个问题。我尝试过中断调用,但似乎什么也没做。

enter image description here

7 个答案:

答案 0 :(得分:9)

有两种方法可以很好地阻止一个线程,另一种方式是邪恶的。

对于所有你需要访问线程的对象(或者在第一种情况下是在该线程上执行的Runnable类)。

因此,您的首要任务是确保您可以访问要停止的所有线程的列表。另请注意,在处理多个线程使用的对象时,您需要确保使用线程安全通信!

现在您有以下选项

中断机制

在每个帖子上调用Thread.interrupt()。如果你处于阻塞函数中,这将在线程上抛出InterruptedException。否则它只会设置isInterrupted()标志,所以你也必须检查它。这是一种非常干净且通用的方法,它将尝试通过此线程中断阻塞函数。然而,许多人不理解如何nicely reactInterruptedException,因此它可能更容易出错。

isRunning flag

在你的帖子中有一个布尔'isRunning'。 while循环调用一个函数'stopRunning()',将此布尔值设置为false。在您的线程中,您会定期读取此布尔值并在设置为false时停止执行。 这个布尔值需要是线程安全的,这可以通过使它volatile(或使用synchronized锁定)来完成。

当你拥有Runnable时,这也很有效,这是目前在线程上运行任务的建议方式(因为你可以轻松地将Runnables移动到Threadpools等。

停止线程(EVIL)

第三种 EVIL 并且已弃用的方法是致电Thread.stop()。这是非常不安全的,可能会导致意外行为,不要这样做!

答案 1 :(得分:2)

确保每个线程内的循环完成 - 如果它在所有线程中完成,则输出中有打印没有意义。请注意,您在每个循环条件中检查的内容是检查当前小时是否不是下午1点,而不是如果还没过一小时。

此外,你的线程垃圾收集,这意味着垃圾收集器负责终止后的销毁 - 但在这种情况下,他们不应该输出任何东西。

答案 2 :(得分:1)

您是否考虑过使用ExecutorService?它的行为更可预测,并避免了线程创建的开销。我的建议是你将while循环包装在一个中并设置1小时的时间限制。

答案 3 :(得分:1)

所有线程共享的 volatile 变量应该有助于实现目标。 volatile变量的重要性在于每个Thread都不会缓存或具有本地副本,但需要直接从主内存中读取。一旦更新,线程将获得新数据。

    public class A{
     public static volatile boolean letThreadsRun = true;
    }

    // inside your Thread class
    @Override
    public void run()
    {    // there will come a point when A.letThreadsRun will be set to false when desired
         while(A.letThreadsRun)
        {

        }
    }
  

如果两个线程都在读取和写入共享变量,那么   使用volatile关键字是不够的。你需要使用   在这种情况下同步,以保证读写   变量是原子的。

这些链接可以帮助您掌握这个概念:

http://tutorials.jenkov.com/java-concurrency/volatile.html

http://java.dzone.com/articles/java-volatile-keyword-0

答案 4 :(得分:1)

如果在主程序完成后这些线程仍在运行,那么将它们设置为守护程序线程可能是合适的。所有非守护程序线程完成后,JVM将退出,从而终止所有剩余的守护程序线程。

如果您启动以下话题:

Thread myThread = new MyThread();
myThread.start();

然后守护它们就像:

Thread myThread = new MyThread();
myThread.setDaemon(true);
myThread.start();

答案 5 :(得分:1)

外部终止线程或依赖kill之类的外部机制来正确终止程序是一种不好的做法。线程应始终设计为自终止,而不是将资源(和共享对象)保留在可能不确定的状态。每当我遇到一个在它应该没有停止的线程时,它总是一个编程错误。检查您的代码,然后在调试器中逐步执行运行循环。

关于你的线程,它应该在小时达到1时自行终止,但如果它低于或高于1,它将不会终止。如果分钟超过59,我会确保时钟的小时计数达到1,并检查它是否以某种方式跳过1并逐渐增加到日落,跳过了唯一的测试值。还要检查clock.getHour()实际上是返回小时数而不是虚拟值或严重错误的东西。

答案 6 :(得分:1)

使用Thread.interrupt()不会阻止线程运行,它只是向你的线程发送一个信号。听取这个信号并采取相应行动是我们的工作。

Thread t = new Thread(new Runnable(){
              public void run(){
                 // look for the signal
                 if(!Thread.interrupted()){
                     // keep doing whatever you're doing
                 }

              }
         });

 // After 1 hour
 t.interrupt();

但是,考虑使用ExecutorService,而不是完成所有这些工作。您可以使用带有静态方法的Executors类来返回不同的线程池。

  

Executors.newFixedThreadPool(10)

  • 创建一个大小为10的固定线程池,并且任何其他作业将进入队列以便稍后处理
  

Executors.newCachedThreadPool()

  • 以0个线程开始并创建新线程,并在所有现有线程忙于某项任务时根据需要将它们添加到池中。这个有一个终止策略,如果一个线程空闲60秒,它将从池中删除该线程
  

Executors.newSingleThreadExecutor()

  • 创建一个将从队列中提取的单个线程,所有已提交的任务将一个接一个地处理。

您可以将相同的Runnable任务提交到线程池。执行者还有获取池的方法,您可以在其中提交计划任务,以及将来要发生的事情

ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(myRunnableTask);

提出您的问题,当您使用线程池时,您可以选择在经过一段时间后关闭它们

service.shutdown();
service.awaitTermination(60, TimeUnit.MINUTES);

很少有事要注意

shutdown()启动有序关闭,其中执行先前提交的任务,但不接受任何新任务。如果已经关闭,调用没有额外的效果。

awaitTermination()正在等待执行程序的状态转到TERMINATED。但首先,如果调用shutdown(),则状态必须转到SHUTDOWN;如果调用shutdownNow(),则必须转到STOP。