スレッドのキャンセルとクローズ


スレッドのキャンセルとクローズ
1.中断不可能なブロックの処理
Javaライブラリでは、多くのブロック可能なメソッドは、InterruptedExceptionを事前に返すか、または投げ出すことによって要求を中断しますが、すべてのブロック可能なメソッドまたはブロックメカニズムが相応に中断できるわけではありません.同期可能なSocket IOまたは組み込みロックの取得待ちによってスレッドがブロックされている場合、割り込み要求はスレッドの割り込み状態のみを設定します.これ以外は何の役にも立ちません.割り込み不可操作の実行によってブロックされたスレッドについては、割り込みのような手段を用いてこれらのスレッドを停止することができるが、これはスレッドがブロックされた原因を知る必要がある.1.Socket I/Oサービスアプリケーションにおいて、最も一般的なブロックI/O形式はソケットの読み取りと書き込みである.InputStreamやOutputStreamのreadやwriteなどの方法では応答が途切れることはないが、最下位のソケットを閉じることでreadやwriteなどの方法でブロックするスレッドをSocketException 2から放出することができる.Selector非同期I/OスレッドがSelectorを呼び出している場合.selectメソッドでブロックすると、closeメソッドまたはwakeupメソッドを呼び出すと、closeSelectorExceptionからスレッドが投げ出され、事前に戻る.ロックを取得内蔵ロックを待つためにスレッドがブロックされている場合、割り込みに応答できません.スレッドはロックを必ず取得できると考えているので、割り込み要求は無視されます.しかし、ロッククラスには、ロックを待機しながら割り込みに応答できるlockInterruptiblyメソッドが提供されています.
2.newTaskForを用いて非標準的なキャンセルをカプセル化する
CallableをExecutorServiceにコミットすると、submitメソッドはFutureを返し、このFutureでタスクをキャンセルできます.新TaskForは、タスクを表すFutureを作成するファクトリメソッドです.新TaskForはまた、FutureとRunnableを拡張したRunnableFutureインタフェースを返すことができます.タスクを表すFutureをカスタマイズすることでFutureを変更できます.camcel動作、例えば、カスタマイズされたキャンセルコードは、ログ記録を実装したり、キャンセル操作の統計を収集したり、中断に応答しない操作をキャンセルしたりすることができます.
3.shutdownNowの限界
shutdownNowでExecutorServiceを強制的に閉じると、実行中のタスクをキャンセルし、コミットされたがまだ開始していないすべてのタスクを返してログに書き込むか、後で処理するために保存しようとします.しかしながら、通常の方法では、タスク自体が何らかのチェックを実行しない限り、タスクが開始されたがまだ終了していないタスクを特定することはできません.これは、タスク自体が実行中のタスクステータスを閉じる過程で知ることができないことを意味します.
import java.util.*;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 *       ,  shutdownNow        ,
 *              
 */
public class TrackingExecutor extends AbstractExecutorService {

    private final ExecutorService exec;

    private final Set tasksCancelledAtShutdown =
            Collections.synchronizedSet(new HashSet());

    public TrackingExecutor() {
        exec = Executors.newCachedThreadPool();
    }

    public List getCancelledTasks() {
        if (!exec.isTerminated()) {
            throw new IllegalStateException();
        }
        return new ArrayList(tasksCancelledAtShutdown);
    }

    /**
     *   execute,          Runnable
     * @param command
     */
    public void execute(final Runnable command) {
        exec.execute(new Runnable() {
            public void run() {
                try {
                    command.run();
                } finally {
                    if (isShutdown() && Thread.currentThread().isInterrupted()) {
                        tasksCancelledAtShutdown.add(command);
                    }
                }
            }
        });

    }

    public void shutdown() {
        exec.shutdown();
    }

    public List shutdownNow() {
        return exec.shutdownNow();
    }

    public boolean isShutdown() {
        return exec.isShutdown();
    }

    public boolean isTerminated() {
        return exec.isTerminated();
    }

    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        return exec.awaitTermination(timeout, unit);
    }
}

4.JVMオフ
4.1フックを閉じる
通常のシャットダウンでは、JVMはまず登録済みのすべてのシャットダウンフックを呼び出し、シャットダウンフックはRuntimeを介している.addShutdownHookに登録されているがまだ開始されていないスレッドでは、JVMはフックを閉じる呼び出し順序を保証することはできません.アプリケーションスレッドを閉じるときに、デーモンまたは非デーモンスレッドがまだ実行されている場合、これらのスレッドは次に閉じるプロセスと同時に実行されます.すべてのシャットダウンフックが終了すると、runFinalizersOnExitがtrueの場合、JVMはターミネータを実行してから停止します.シャットダウンフックまたはターミネータが完了していない場合、通常のシャットダウンプロセスが停止し、JVMが強制的にシャットダウンされる必要があります.強制的にシャットダウンされると、フックはシャットダウンされずにJVMのみがシャットダウンされます.フックを閉じると、一時ファイルの削除やオペレーティングシステムで自動的にクリアできないリソースのクリアなど、サービスまたはアプリケーションのクリーンアップ作業を実現できます.
public void start()
{
    Runtime.getRuntime().addShutdownHook(new Thread(){
        public void run()
        {
            try{
                LogService.stop();
            }
            catch(InterruptedException ignored)
            {

            }
        }
    });
}

4.2デーモンスレッド
スレッドには、通常のスレッドとデーモンスレッドの2種類があります.JVMの起動時に作成されるすべてのスレッドのうち、メインスレッド以外は、他のスレッドはすべてデーモンスレッドです(ゴミ回収機や補助作業を行う他のスレッドなど)新しいスレッドを作成すると、新しいスレッドは作成したスレッドのデーモン状態を継承します.したがって、デフォルトでは、メインスレッドが作成したすべてのスレッドは通常のスレッドです.通常のスレッドとデーモンスレッドの違いは、スレッドが終了したときに発生する操作のみです.1つのスレッドが終了した場合、JVMは他の実行中のスレッドをチェックします.これらのスレッドがデーモンスレッドである場合、JVMは正常に動作を終了します.JVMが停止すると、まだ存在するデーモンスレッドはすべて破棄され、finallyコードブロックもボリュームスタックも実行されません.JVMは直接終了します.デーモンスレッドをできるだけ少なく使用し、クリーンアップを行わずに安全に破棄できる操作は少ない.
4.3ターミネータ
メモリリソースが必要でない場合は、ゴミ回収器で回収できますが、ファイルハンドルやソケットなどの他のリソースについては、必要でない場合はオペレーティングシステムに明示的に返却する必要があります.この機能を実現するために、GCはfinalizeメソッドを定義したオブジェクトに対して特殊な処理を行います.回収器が彼らを解放した後、finalizeメソッドを呼び出し、いくつかの持続的なリソースが解放されることを保証します.ターミナルの使用を避ける