繁体   English   中英

如何从另一个线程中断一个线程中的循环?

[英]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()中断状态设置中断 ,但实际上不会中断线程执行。 threadrun方法在被中断后再次被调用。 因为我们在循环开始时检查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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM