在 while 语句 运行 后结束 Java 个线程
End Java threads after a while statement has been run
我的程序完成后,我在结束线程时遇到问题。我 运行 一个线程时钟对象,它工作得很好,但我需要在时间“==”一小时那个位似乎工作时结束所有线程我只需要知道如何结束它们。这是我拥有的代码示例,这是 运行 方法中唯一的 运行s 除了上面定义的一个 int 代码。
@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 的调试模式下继续观察 运行ning 的线程时,它们会在一小时后保持 运行ning,但不确定如何解决此问题。我试过中断调用,但它似乎什么也没做。
确保每个线程内的循环都完成 - 如果它在所有线程中完成,那么输出中有打印件就没有意义。请注意,您在每个循环条件中检查的内容是检查当前时间是否不是下午 1 点,而不是检查一个小时是否已经过去。
此外,您的线程已被垃圾收集,这意味着垃圾收集器负责在终止后销毁它们 - 但在这种情况下,它们不应输出任何内容。
有两种停止线程的好方法和一种坏方法。
对于所有你需要访问线程的对象(或者在第一种情况下是在该线程上执行的 Runnable class)。
因此,您的首要任务是确保您可以访问要停止的所有线程的列表。另请注意,在处理多个线程使用的对象时,您需要确保使用线程安全通信!
现在您有以下选项
中断机制e
在每个线程上调用 Thread.interrupt()
。如果您处于阻塞函数中,这将在线程上抛出一个 InterruptedException
。否则它只会将 isInterrupted()
flag, so you have to check this as well. This is a very clean and versatile way that will try to interrupt blocking functions by this thread. However many people don't understand how to nicely react 设置为 InterruptedException
,因此更容易出现错误。
正在运行标志
在您的主题中添加一个布尔值 'isRunning'。 while 循环调用函数 'stopRunning()' 将此布尔值设置为 false。在您的线程中,您会定期读取此布尔值并在将其设置为 false 时停止执行。
这个布尔值需要是线程安全的,这可以通过使其成为 volatile
(或使用 synchronized
锁定)来完成。
当你有一个 Runnable
时,这也很有效,这是目前 运行 线程任务的推荐方式(因为你可以轻松地将 Runnables
移动到 Threadpools
等
停止线程(邪恶)
第三种 EVIL 且已弃用的方法是调用 Thread.stop()
。这是非常不安全的,可能会导致意外行为,请不要这样做!
您是否考虑过使用 ExecutorService ?它的行为更可预测,并避免了线程创建的开销。我的建议是将 while 循环包含在一个循环中并设置 1 小时的时间限制。
所有线程共享的 volatile 变量应该有助于实现目标。 volatile 变量的重要性在于每个线程都不会缓存或具有本地副本,而是需要直接从主内存中读取。更新后,线程将获得新数据。
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)
{
}
}
If two threads are both reading and writing to a shared variable, then
using the volatile keyword for that is not enough. You need to use
synchronization in that case to guarantee that the reading and writing
of the variable is atomic.
以下链接可以帮助您掌握概念:
如果在您的主程序完成后这些线程仍然 运行,那么将它们设置为守护线程可能是合适的。 JVM 将在所有非守护线程完成后退出,杀死所有剩余的守护线程。
如果你开始这样的线程:
Thread myThread = new MyThread();
myThread.start();
然后对它们进行守护进程就很简单:
Thread myThread = new MyThread();
myThread.setDaemon(true);
myThread.start();
从外部终止线程或依赖诸如 kill 之类的外部机制来正确终止程序是一种不好的做法。线程应始终设计为自我终止,而不是让资源(和共享对象)处于潜在的不确定状态。每次遇到线程没有按预期停止的时候,总是编程错误。去检查你的代码,然后在调试器中单步执行 运行 循环。
关于你的线程,它应该在小时数达到1时自行终止,但如果低于或高于1,则不会终止。如果分钟超过 59,我会确保时钟的小时计数达到 1,并且还会检查它是否不会以某种方式跳过 1 并递增到日落,跳过了唯一的测试值。还要检查 clock.getHour() 实际上返回的是小时计数,而不是虚拟值或一些严重不正确的东西。
使用 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。您可以将执行器 class 与静态方法一起用于 return 不同的线程池。
Executors.newFixedThreadPool(10)
- 创建一个大小为 10 的固定线程池,任何更多的作业将进入队列等待稍后处理
Executors.newCachedThreadPool()
- 从 0 个线程开始并创建新线程,如果所有现有线程都忙于某个任务,则根据需要将它们添加到池中。这个有一个终止策略,如果一个线程空闲 60 秒,它将从池中删除该线程
Executors.newSingleThreadExecutor()
- 创建一个从队列中获取数据的线程,所有提交的任务将一个接一个地处理。
您可以将相同的 Runnable 任务提交到您的线程池。 Executors 也有获取池的方法,你可以将计划任务提交到池中,你希望在未来发生的事情
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(myRunnableTask);
关于你的问题,当你使用线程池时,你可以选择在一段时间后关闭它们,就像这样
service.shutdown();
service.awaitTermination(60, TimeUnit.MINUTES);
注意事项
shutdown() 启动有序关闭,执行先前提交的任务,但不会接受新任务。如果已经关闭,调用没有额外效果。
awaitTermination() 正在等待执行程序的状态变为 TERMINATED。但是首先,如果调用 shutdown() 则状态必须转到 SHUTDOWN,如果调用 shutdownNow() 则状态必须转到 STOP。
我的程序完成后,我在结束线程时遇到问题。我 运行 一个线程时钟对象,它工作得很好,但我需要在时间“==”一小时那个位似乎工作时结束所有线程我只需要知道如何结束它们。这是我拥有的代码示例,这是 运行 方法中唯一的 运行s 除了上面定义的一个 int 代码。
@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 的调试模式下继续观察 运行ning 的线程时,它们会在一小时后保持 运行ning,但不确定如何解决此问题。我试过中断调用,但它似乎什么也没做。
确保每个线程内的循环都完成 - 如果它在所有线程中完成,那么输出中有打印件就没有意义。请注意,您在每个循环条件中检查的内容是检查当前时间是否不是下午 1 点,而不是检查一个小时是否已经过去。
此外,您的线程已被垃圾收集,这意味着垃圾收集器负责在终止后销毁它们 - 但在这种情况下,它们不应输出任何内容。
有两种停止线程的好方法和一种坏方法。
对于所有你需要访问线程的对象(或者在第一种情况下是在该线程上执行的 Runnable class)。
因此,您的首要任务是确保您可以访问要停止的所有线程的列表。另请注意,在处理多个线程使用的对象时,您需要确保使用线程安全通信!
现在您有以下选项
中断机制e
在每个线程上调用 Thread.interrupt()
。如果您处于阻塞函数中,这将在线程上抛出一个 InterruptedException
。否则它只会将 isInterrupted()
flag, so you have to check this as well. This is a very clean and versatile way that will try to interrupt blocking functions by this thread. However many people don't understand how to nicely react 设置为 InterruptedException
,因此更容易出现错误。
正在运行标志
在您的主题中添加一个布尔值 'isRunning'。 while 循环调用函数 'stopRunning()' 将此布尔值设置为 false。在您的线程中,您会定期读取此布尔值并在将其设置为 false 时停止执行。
这个布尔值需要是线程安全的,这可以通过使其成为 volatile
(或使用 synchronized
锁定)来完成。
当你有一个 Runnable
时,这也很有效,这是目前 运行 线程任务的推荐方式(因为你可以轻松地将 Runnables
移动到 Threadpools
等
停止线程(邪恶)
第三种 EVIL 且已弃用的方法是调用 Thread.stop()
。这是非常不安全的,可能会导致意外行为,请不要这样做!
您是否考虑过使用 ExecutorService ?它的行为更可预测,并避免了线程创建的开销。我的建议是将 while 循环包含在一个循环中并设置 1 小时的时间限制。
所有线程共享的 volatile 变量应该有助于实现目标。 volatile 变量的重要性在于每个线程都不会缓存或具有本地副本,而是需要直接从主内存中读取。更新后,线程将获得新数据。
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)
{
}
}
If two threads are both reading and writing to a shared variable, then using the volatile keyword for that is not enough. You need to use synchronization in that case to guarantee that the reading and writing of the variable is atomic.
以下链接可以帮助您掌握概念:
如果在您的主程序完成后这些线程仍然 运行,那么将它们设置为守护线程可能是合适的。 JVM 将在所有非守护线程完成后退出,杀死所有剩余的守护线程。
如果你开始这样的线程:
Thread myThread = new MyThread();
myThread.start();
然后对它们进行守护进程就很简单:
Thread myThread = new MyThread();
myThread.setDaemon(true);
myThread.start();
从外部终止线程或依赖诸如 kill 之类的外部机制来正确终止程序是一种不好的做法。线程应始终设计为自我终止,而不是让资源(和共享对象)处于潜在的不确定状态。每次遇到线程没有按预期停止的时候,总是编程错误。去检查你的代码,然后在调试器中单步执行 运行 循环。
关于你的线程,它应该在小时数达到1时自行终止,但如果低于或高于1,则不会终止。如果分钟超过 59,我会确保时钟的小时计数达到 1,并且还会检查它是否不会以某种方式跳过 1 并递增到日落,跳过了唯一的测试值。还要检查 clock.getHour() 实际上返回的是小时计数,而不是虚拟值或一些严重不正确的东西。
使用 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。您可以将执行器 class 与静态方法一起用于 return 不同的线程池。
Executors.newFixedThreadPool(10)
- 创建一个大小为 10 的固定线程池,任何更多的作业将进入队列等待稍后处理
Executors.newCachedThreadPool()
- 从 0 个线程开始并创建新线程,如果所有现有线程都忙于某个任务,则根据需要将它们添加到池中。这个有一个终止策略,如果一个线程空闲 60 秒,它将从池中删除该线程
Executors.newSingleThreadExecutor()
- 创建一个从队列中获取数据的线程,所有提交的任务将一个接一个地处理。
您可以将相同的 Runnable 任务提交到您的线程池。 Executors 也有获取池的方法,你可以将计划任务提交到池中,你希望在未来发生的事情
ExecutorService service = Executors.newFixedThreadPool(10);
service.execute(myRunnableTask);
关于你的问题,当你使用线程池时,你可以选择在一段时间后关闭它们,就像这样
service.shutdown();
service.awaitTermination(60, TimeUnit.MINUTES);
注意事项
shutdown() 启动有序关闭,执行先前提交的任务,但不会接受新任务。如果已经关闭,调用没有额外效果。
awaitTermination() 正在等待执行程序的状态变为 TERMINATED。但是首先,如果调用 shutdown() 则状态必须转到 SHUTDOWN,如果调用 shutdownNow() 则状态必须转到 STOP。