5

Solaris 10 で Java 1.5 を実行しています。私のプログラムは、Java 同時実行パッケージと log4j-1.2.12.jar を使用して特定の情報をログに記録するスタンドアロンの Java プログラムです。主なロジックは以下のとおりです

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

私のプログラムの実行中に、時々(常にではありませんが)このエラーが発生します...

executor.shutdown(); 

super.run(); によって内部的に使用されるワーカー セットからワーカーが既に削除されているため、呼び出しから戻った後に AppThread を中断することはできThreadPoolExecutorません。エグゼキューターはその時点から AppThread への参照を持っていません。

ところで:ログファイルにアクセスでき、サイズは十分に大きいです。

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は次の行です。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;
    }
}

別の問題は、の原因をデバッグするためにjava.io.InterruptedIOException、追加したことです

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

runAppThreadのメソッドの finally 句で。whenInterruptedException が finally 句でキャッチされると、オーバーライドinterrupt()メソッドが呼び出されることはありません。AppThread を中断するのは誰ですか? 同じ男の原因java.io.InterruptedIOExceptionですか?

4

3 に答える 3

9

はい:

shutdownNow アクティブに実行中のすべてのタスクの停止を試み、待機中のタスクの処理を停止し、実行を待機していたタスクのリストを返します。

アクティブに実行中のタスクの処理を停止するための最善の努力以外の保証はありません。たとえば、典型的な実装はThread.interrupt() によってキャンセルされるため、割り込みに応答しないタスクは決して終了しない可能性があります。

ジャバドク

shutdown()の代わりに使用するだけですshutdownNow()。強制的に呼び出しshutdownNow()ている場合は、これが予期されることです。JVM は適切に I/O を中断し、できるだけ速くスレッドをシャットダウンします。

ただし、ロギングがアプリケーションのボトルネックにならないようにします。プログラムの実行中にいくつかのスレッド ダンプを作成するだけで、スレッドが I/O を書き込みまたは待機する頻度を確認できます。貧乏人のプロファイリング。

于 2011-09-27T20:53:05.797 に答える
2

ワーカー スレッドの中断は、実際にはフレームワークの機能であり、. の動作が文書化されています。Executorinterrupt()shutdownNow()

これが必要ない場合は、呼び出してください。これはワーカー スレッドでshutdown()はなく、新しいタスクの受け入れを停止するだけです。interrupt()Executor

于 2011-09-27T20:53:56.523 に答える
0

私も同様の問題を抱えています。私の研究はこれまでのところThread.interrupt()、割り込みフラグを設定しています。これにより、Java スタックの奥深くで IO 操作が中断されます。ただし、通常、IO メソッドは をスローするように宣言されていませんInterruptedException

代わりにInterruptedIOExceptionがスローされ、スレッドの中断状態がクリアされます! . IOException( catch ) を期待する Worker を作成した場合は、個別に catchし、catch 句InterruptedIOExceptionで呼び出す必要があります。Thead.currentThread().interrupt()

于 2015-06-11T08:11:02.887 に答える