我的程序完成后,我遇到了一个结束线程的问题。我运行一个线程时钟对象,它工作得很好,但我需要结束所有线程,当时间'=='一小时这一点似乎工作我只需要知道如何结束它们。下面是我所拥有的代码示例,除了在此代码上面定义的一个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的调试模式下运行的线程时,它们会在一小时后继续运行,但不确定如何解决这个问题。我尝试过中断调用,但似乎什么也没做。
答案 0 :(得分:9)
有两种方法可以很好地阻止一个线程,另一种方式是邪恶的。
对于所有你需要访问线程的对象(或者在第一种情况下是在该线程上执行的Runnable类)。
因此,您的首要任务是确保您可以访问要停止的所有线程的列表。另请注意,在处理多个线程使用的对象时,您需要确保使用线程安全通信!
现在您有以下选项
在每个帖子上调用Thread.interrupt()
。如果你处于阻塞函数中,这将在线程上抛出InterruptedException
。否则它只会设置isInterrupted()
标志,所以你也必须检查它。这是一种非常干净且通用的方法,它将尝试通过此线程中断阻塞函数。然而,许多人不理解如何nicely react到InterruptedException
,因此它可能更容易出错。
在你的帖子中有一个布尔'isRunning'。 while循环调用一个函数'stopRunning()',将此布尔值设置为false。在您的线程中,您会定期读取此布尔值并在设置为false时停止执行。
这个布尔值需要是线程安全的,这可以通过使它volatile
(或使用synchronized
锁定)来完成。
当你拥有Runnable
时,这也很有效,这是目前在线程上运行任务的建议方式(因为你可以轻松地将Runnables
移动到Threadpools
等。
第三种 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关键字是不够的。你需要使用 在这种情况下同步,以保证读写 变量是原子的。
这些链接可以帮助您掌握这个概念:
答案 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)
Executors.newCachedThreadPool()
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。