Java线程中断仅等待,加入和睡眠

时间:2019-10-14 16:20:41

标签: java multithreading

Thread.interrupt()

  

中断此线程。除非当前线程   正在中断自身(始终允许),checkAccess   调用此线程的方法,这可能会导致SecurityException   被扔掉。

     

如果在调用 wait(),wait(long),   或Object类或join()的wait(long,int)方法,   join(long),join(long,int),sleep(long)或sleep(long,int),方法   此类,则将清除其中断状态并将其   收到InterruptedException。

     

如果此线程在 I / O操作中被阻止,   然后中断InterruptibleChannel,将关闭该线程的   中断状态将被设置,线程将收到一个   ClosedByInterruptException。

     

如果此线程在选择器中被阻止,则该线程的中断   状态将被设置,它将立即从选择中返回   操作,可能具有非零值,就像选择器的   唤醒方法被调用。

     

如果先前的条件均不成立,则此线程的中断   状态将被设置。

     

中断未运行的线程不会产生任何效果。

让我们说我们有以下代码:

AtomicBoolean thread1Done = new AtomicBoolean(false);

//write in file
Thread thread1 = new Thread(() -> {

    try(var writer = Files.newBufferedWriter(Paths.get("foo.txt"))){

        for(int i = 0; i < 10000; i++){
            writer.write(i);
            writer.newLine();
        }

    }catch(Exception e){ e.printStackTrace(); }

    thread1Done.set(true);

});

//interrupt thread1
Thread thread2 = new Thread(() -> {

    while(!thread1Done.get()){
        thread1.interrupt();
    }

});

thread2.start();
thread1.start();

thread1永远不会在文件中写入任何内容,因为thread1.interrupt()中的thread2

它始终以java.nio.channels.ClosedByInterruptException的{​​{1}}结尾,writer.newLine();为空。

是否可以仅中断foo.txt并忽略其余部分?

我在Windows10 x64上使用JDK10运行代码。

2 个答案:

答案 0 :(得分:1)

按目前的情况运行代码,以使Thread 1完成向输出文本文件中写入10k行的操作,换言之Thread 2中断,但是Thread 1中没有以下语句: strong>可中断。这是因为(我想)BufferedWriter使用不间断I / O 打开文件。

如果您希望Thread 1中的长循环是可中断的,则可以在长循环中添加以下检查:

for(int i = 0; i < 10000; i++){
    if (Thread.currentThread().isInterrupted()) {    //interruptible loop
        break;
    }
    writer.write(i);
    writer.newLine();
    System.out.println(i);
}

然后,将Thread 2的中断延迟10毫秒,我得到的是只有几百个条目被写入文件(没有延迟,它会立即被中断)。

当我交换Thread 1以使用可中断频道
(与FileChannel extends AbstractInterruptibleChannel一样)时:

Thread thread1 = new Thread(() -> {
    FileChannel fc = null;
    try ( 
       FileChannel fc = FileChannel.open(Paths.get("foo.txt"), 
                        StandardOpenOption.CREATE, StandardOpenOption.WRITE);
    )
    {
       fc = FileChannel.open(Paths.get("foo.txt"), 
          StandardOpenOption.CREATE, StandardOpenOption.WRITE
       );

       for(int i = 0; i < 10000; i++){
           fc.write(ByteBuffer.wrap(("" + i).getBytes()));
           fc.write(ByteBuffer.wrap(("\n").getBytes()));
           System.out.println(i);
       }
    } catch (Exception e) {
       e.printStackTrace();
    } 
}

...我确实得到了很好的可中断文件写入线程。

答案 1 :(得分:1)

如果您想要的是仅在等待,联接和睡眠调用而不是IO操作阻止的情况下中断线程,则可以在调用中断方法之前简单地检查线程状态。您可以参考api和以下链接中的不同状态。

https://docs.oracle.com/javase/10/docs/api/java/lang/Thread.State.html

示例代码可能类似于下面的代码。

while ( ( thread1.getState() == Thread.State.WAITING || thread1.getState() == Thread.State.TIMED_WAITING ) && !thread1Done.get()) {
    thread1.interrupt();
}