[英]How do I break a loop in one Thread from another Thread?
我是Java的新手,我正在尝试使用一个Thread来完成另一个Thread中的循环,而不管循环的状态如何。
public static void main(String[] args) {
// Either start the other thread here
while(true){
// Or here, not quite sure
// Do stuff
}
}
}
public class Timer implements Runnable{
@Override
public void run() {
long start = System.currentTimeMillis();
while(true) {
long current = System.currentTimeMillis();
if(current - start == 10000){
// How do I notify the loop in main to break?
break;
}
}
}
}
我想要做的是在10秒后结束主循环,无论其循环状态如何,因为循环包含从System.in
读取的Scanner
,并且它需要在10秒后停止,无论从何处读取键盘与否。 我认为最好的解决方案是让计时器Thread运行,计算秒数,然后在10秒后以某种方式通知另一个Thread中的循环,但是,我不知道如何实现这个...
如果您的目标是在10秒后停止循环,则没有理由使用其他线程。 只需在当地查看时间:
public class Main {
public static void main(String[] args) {
// Instructions
long start = System.currentTimeMillis();
do {
//Instructions
//Instructions
//...
//Instructions
} while (System.currentTimeMillis() - start < 10000);
}
}
这样的事情怎么样:
public static void main(String[] args) {
// Instructions
AtomicBoolean shouldStop = new AtomicBoolean(false);
Timer timer = new Timer(shouldStop);
// start the timer thread
while(true){
if (shouldStop.get()) {
break;
}
//Instructions
}
}
}
public class Timer implements Runnable{
private final AtomicBoolean shouldStop;
public Timer(AtomicBoolean shouldStop) {
this.shouldStop = shouldStop;
}
@Override
public void run() {
long start = System.currentTimeMillis();
while(true){
long current = System.currentTimeMillis();
if(current - start == 10000) {
shouldStop.set(true);
break;
}
}
}
}
解决问题最安全的方法是使用volatile变量:
public class Main {
private static volatile boolean keepRunning = false;
public static void main(String[] args) {
keepRunning = true;
while(keepRunning) {
//Instructions
//...
//Instructions
}
}
}
public class Timer implements Runnable {
@Override
public void run() {
long start = System.currentTimeMillis();
while(true){
long current = System.currentTimeMillis();
if(current - start == 10000){
// Notify the loop in Main to break
keepRunning = false;
break;
}
}
}
}
不要重新发明轮子。 使用ExecutorService
和带超时的get()
:
ExecutorService executor = Executors.newSingleThreadExecutor();
// Here's a lambda, but you could use an instance of a normal Runnable class
Runnable runnable = () -> {
while(true){
// Do stuff
}
};
Future<?> future = executor.submit(runnable);
try {
future.get(10, TimeUnit.SECONDS);
} catch (TimeoutException e) {
// the task timed out
future.cancel(true); // this will kill the running thread
} catch (InterruptedException | ExecutionException e) {
// the runnable exploded
}
有很多解决方案。 这是其中之一:
public class Main {
public static void main(String... args) {
Thread thread = () -> {
while(true) {
// We call Thread.interrupted to check the interrupted status of the Thread.
// This method also clears the interrupted status of the Thread.
if(Thread.interrupted()) {
break;
}
// code...
}
}
Thread timer = () -> {
long start = System.currentTimeMillis();
while(true) {
long current = System.currentTimeMillis();
if(current - start == 10_000){ // underscore for clarity
// This causes the thread to interrupt. The next pass
// in our loop in "thread" will first check its interrupted status
// before continuing, and will break if the status is interrupted
thread.interrupt();
break;
}
}
}
// wrap in synchronized block to ensure both threads run simultaneously
synchronized(Main.class) {
thread.start();
timer.start();
}
}
}
在这个解决方案中,我们使用中断在thread
中断中进行while循环。 中断在正在执行的任何时刻停止正常的线程操作,但前提是线程调用抛出InterruptedException
的方法,并且线程在catch块中返回(或中断)。 Thread.interrupt()
将中断状态设置为中断 ,但实际上不会中断线程执行。 thread
的run
方法在被中断后再次被调用。 因为我们在循环开始时检查Thread.interrupted()
,所以在循环进入时循环将中断,并且run
退出并且Thread停止运行。 使用Thread.interrupted()
,您必须在同一个线程中检查其中断状态,然后选择清除状态时要执行的操作。
作为旁注,如果循环中我们唯一的分支(if语句)检查该线程的中断状态,那么如果我们简单地将while循环声明为while(!Thread.interrupted())
,那么它可能更容易阅读并且效率更高while(!Thread.interrupted())
。 否则它应保持原样。
其他解决方案在这里通过其他一些答案来说明,尽管有些解决方案以不同的方式回答您的问题 。 其他一些解决方案包括使用Oliver Dain回答的AtomicBoolean; 另一个使用全局锁定对象和volatile布尔值或AtomicBoolean。
有许多解决方案,但在大多数用例中,中断解决方案似乎是最简单和最方便的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.