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

时间:2017-01-06 01:09:14

标签: java multithreading timer while-loop

我是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秒后在main中结束循环,无论其循环状态如何,因为循环包含来自Scanner的{​​{1}}读数,并且需要在之后停止无论键盘读取了什么,都是10秒。我认为最好的解决方案是让计时器Thread运行,计算秒数,然后在10秒后以某种方式通知另一个Thread中的循环,但是,我不知道如何实现这个... < / p>

5 个答案:

答案 0 :(得分:3)

如果您的目标是在10秒后停止循环,则没有理由使用其他线程。只需在当地检查时间:

public class Main {
    public static void main(String[] args) {
        // Instructions

        long start = System.currentTimeMillis();
        do {
            //Instructions
            //Instructions
            //...
            //Instructions   
        } while (System.currentTimeMillis() - start < 10000);
    }
}

答案 1 :(得分:2)

这样的事情怎么样:

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;
            }
        }
    }
}

答案 2 :(得分:2)

解决问题最安全的方法是使用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;
            }
        }
    }

}

答案 3 :(得分:2)

不要重新发明轮子。使用ExecutorServiceget()超时:

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
}

答案 4 :(得分:0)

有很多解决方案。这是其中之一:

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();
        }
    }
}

说明

在此解决方案中,我们使用 interrupts 来使thread中的while循环中断。中断在正在执行的任何点停止正常的线程操作,但前提是线程调用抛出InterruptedException的方法,并且线程在catch块中返回(或中断)。 Thread.interrupt()interrupt status设置为中断,但实际上不会中断线程的执行。中断后再次调用run thread方法。由于我们在循环开始时检查Thread.interrupted(),因此循环进入时循环将中断,并且run退出并且线程停止运行。使用Thread.interrupted()时,您必须在同一个线程中检查其中断状态,然后选择清除状态时要执行的操作。

作为旁注,如果循环中我们唯一的分支(if语句)检查该线程的中断状态,那么如果我们简单地将while循环声明为{,那么它可能更容易阅读并且更有效率{1}}。否则它应保持不变。

其他解决方案

其他解决方案在这里通过其他一些答案进行说明,但有些解决方案以不同的方式解答整个问题。其他一些解决方案包括使用Oliver Dain回答的AtomicBoolean;另一个使用全局lock object和易失性布尔值或AtomicBoolean。

有许多解决方案,但在大多数用例中,中断解决方案似乎是最简单和最方便的。