Thread.interrupt() 和 java.io.InterruptedIOException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7575446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 20:34:03  来源:igfitidea点击:

Thread.interrupt() and java.io.InterruptedIOException

javamultithreadinglog4jjava-iojava.util.concurrent

提问by huahua

I'm running Java 1.5 on Solaris 10. My program is a standalone java program, using java concurrency package and log4j-1.2.12.jar to log certain information. primary logic is as below

我在 Solaris 10 上运行 Java 1.5。我的程序是一个独立的 java 程序,使用 java 并发包和 log4j-1.2.12.jar 来记录某些信息。主要逻辑如下

ExecutorService executor = new AppThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(Integer.MAX_VALUE), new AppThreadFactory("BSRT", true), new ThreadPoolExecutor.CallerRunsPolicy());
        CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(executor);
        for (final Integer id : taskList) {
            Callable<Integer> c = new Callable<Integer>() {
                public Integer call() throws Exception {
                    int newId = DB operation(id);
                    return newId;
                }
            };
            completionService.submit(c);
        }
        logger.debug("Start retrievie result");
        for (Integer id : taskList) {
            try {
                Future<Integer> future = completionService.poll(1, TimeUnit.SECONDS);               
                Integer taskId=null;
                if (future != null) {
                    logger.debug("future is obtained.");
                    taskId = future.get();
                } else {
                    logger.error("wait too long and get nothing!");
                    break;
                }
                if (taskId != null) {
                    taskIdList.add(taskId);
                }
            } catch (ExecutionException ignore) {
                // log the cause and ignore this aborted task,coninue with
                // next available task.
                logger.warn(ignore.getCause());
            } catch (InterruptedException e) {
                logger.warn("interrupted...");
                // Re-assert the thread's interrupted status
                Thread.currentThread().interrupt();
            }
        }executor.shutdown();

During the execution of my program, Sometimes (not always) I'm getting this error ...

在我的程序执行期间,有时(并非总是)我收到此错误...

executor.shutdown(); 

will not be able to interrupt AppThread after return from the call super.run();because the woker is already removed from workers set used internally by ThreadPoolExecutor, executor does not have reference to AppThread from that point of time.

从调用返回后将无法中断 AppThread,super.run();因为 waker 已经从 内部使用的工作人员集中删除ThreadPoolExecutor,执行程序从那个时间点开始没有对 AppThread 的引用。

btw: the log file is accessible and size is big enough.

顺便说一句:日志文件可以访问并且大小足够大。

log4j:ERROR Failed to flush writer,
java.io.InterruptedIOException
       at java.io.FileOutputStream.writeBytes(Native Method)
       at java.io.FileOutputStream.write(FileOutputStream.java:260)
       at sun.nio.cs.StreamEncoder$CharsetSE.writeBytes(StreamEncoder.java:336)
       at sun.nio.cs.StreamEncoder$CharsetSE.implFlushBuffer(StreamEncoder.java:404)
       at sun.nio.cs.StreamEncoder$CharsetSE.implFlush(StreamEncoder.java:408)
       at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:152)
       at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:213)
       at org.apache.log4j.helpers.QuietWriter.flush(QuietWriter.java:57)
       at org.apache.log4j.WriterAppender.subAppend(WriterAppender.java:315)
       at org.apache.log4j.DailyRollingFileAppender.subAppend(DailyRollingFileAppender.java:358)
       at org.apache.log4j.WriterAppender.append(WriterAppender.java:159)
       at org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:230)
       at org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:65)
       at org.apache.log4j.Category.callAppenders(Category.java:203)
       at org.apache.log4j.Category.forcedLog(Category.java:388)
       at org.apache.log4j.Category.debug(Category.java:257)
       at AppThread.run( AppThread.java: 33)  

33 is the line: if (debug) logger.info("Exiting " + getName());

33 是一行: if (debug) logger.info("Exiting " + getName());

import java.util.concurrent.atomic.AtomicInteger;

import org.apache.log4j.Logger;

public class AppThread extends Thread {
    public static final String DEFAULT_NAME = "MyAppThread";
    private static volatile boolean debugLifecycle = false;
    private static final AtomicInteger created = new AtomicInteger();
    private static final AtomicInteger alive = new AtomicInteger();
    private static final Logger logger = Logger.getLogger(AppThread.class);
    private boolean dump = false;

    public AppThread(Runnable r) {
        this(r, DEFAULT_NAME);
    }

    public AppThread(Runnable runnable, String name) {
        super(runnable, name + "-" + created.incrementAndGet());
        logger.debug(name + "'s constructor running");
    }

    public void interrupt() {
        if (!dump) {
            super.interrupt();
        }
        if (dump) {
            logger.debug("interrupt : " + getName() + " <<<");
            Thread.dumpStack();
            logger.debug("interrupt : " + getName() + " >>>");
        }
    }

    public void run() {
        boolean debug = debugLifecycle;
        if (debug)
            logger.info("Created " + getName());
        try {
            alive.incrementAndGet();
            super.run();
            logger.debug("running!");
        } finally {
            alive.decrementAndGet();
            dump = true;
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                logger.debug(e);
            }
            if (debug)
                logger.info("Exiting " + getName());
        }
    }

    public static int getThreadsCreated() {
        return created.get();
    }

    public static int getThreadsAlive() {
        return alive.get();
    }

    public static boolean getDebug() {
        return debugLifecycle;
    }

    public static void setDebug(boolean b) {
        debugLifecycle = b;
    }
}

Another problem is that in order to debug the cause of java.io.InterruptedIOException, I added

另一个问题是,为了调试 的原因java.io.InterruptedIOException,我添加了

     try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            logger.debug(e);
        }

in finally clause in the runmethod for AppThread. when InterruptedExceptionis catched in the finally clause, the override interrupt()method is never called. so who interrupt AppThread? is the same guy cause java.io.InterruptedIOException?

runAppThread的方法中的 finally 子句中。当InterruptedException在 finally 子句中被捕获时,interrupt()从不调用覆盖方法。那么谁来中断 AppThread 呢?是同一个人的原因java.io.InterruptedIOException吗?

回答by Tomasz Nurkiewicz

Yes:

是的:

shutdownNow Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.

There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.

shutdownNow 尝试停止所有正在执行的任务,停止等待任务的处理,并返回等待执行的任务列表。

除了尽力尝试停止处理正在执行的任务之外,没有任何保证。例如,典型的实现将通过 Thread.interrupt() 取消,因此任何未能响应中断的任务可能永远不会终止。

JavaDoc.

文档

Simply use shutdown()instead of shutdownNow(). When you are forcibly calling shutdownNow()this is what you should expect - JVM gracefully interrupts I/O and shuts down the thread as fast as possible.

只需使用shutdown()而不是shutdownNow(). 当您强行调用时,shutdownNow()这是您应该期待的 - JVM 优雅地中断 I/O 并尽快关闭线程。

However I would make sure that logging isn't the bottleneck in your application. Simply make few thread dumps during the execution of your program and see how often threads are writing or waiting for I/O. Poor man's profiling.

但是,我会确保日志记录不是您的应用程序中的瓶颈。只需在程序执行期间进行少量线程转储,然后查看线程写入或等待 I/O 的频率。穷人的侧写。

回答by Philipp Reichart

Interrupting the worker threads is actually a featureof the Executorframework to allow worker threads to gracefully shut down when asked to do so through interrupt(). It's documented behavior for shutdownNow().

中断工作线程实际上是框架的一个功能,它Executor允许工作线程在通过interrupt(). 这是shutdownNow().

If you don't want this, call shutdown()-- it won't interrupt()your worker threads, the Executorwill just stop accepting new tasks.

如果你不想要这个,调用shutdown()——它不会是interrupt()你的工作线程,它Executor只会停止接受新任务。

回答by entropie

I have similar problems. My research went so far that Thread.interrupt()sets the interrupt flag. This leads to an interrupted IO operation deep in the Java Stack. But the IO methods are typically not declared to throw an InterruptedException.

我有类似的问题。我的研究到目前为止Thread.interrupt()设置了中断标志。这会导致 Java 堆栈深处的 IO 操作中断。但是 IO 方法通常不会声明为抛出InterruptedException.

Instead an InterruptedIOExceptionis thrown and the interrupted state of the Thread is cleared!. If you wrote a Worker that expects (catches) IOExceptions, you have to catch the InterruptedIOExceptionseparately and call Thead.currentThread().interrupt()in the catch clause.

而是InterruptedIOException抛出an并清除 Thread中断状态!. 如果您编写了一个期望 (catches) IOExceptions的 Worker,则必须InterruptedIOException单独捕获并调用Thead.currentThread().interrupt()catch 子句。