JAvaスレッド中断メカニズム

7898 ワード

フラグ変数の使用


volatileタイプのフラグ変数制御スレッドが中断されていることを確認すると、volatileタイプのフラグ変数を使用しないとjvmのメモリ最適化にデッドサイクルが発生します.
public class StopThread {
    private static volatile boolean stopRequested;

    public static void main(String[] args) throws InterruptedException {
        Thread backgroundThread = new Thread(new Runnable() {
            public void run() {
                int i = 0;
                while (!stopRequested) {
                    i++;
                }
            }
        });

        backgroundThread.start();

        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }
}

interrupt割り込み


上記のようなフラグ変数によってスレッドを割り込まなければ、Threadクラスの関連手法によって割り込みを行うようにしてもよい
header 1
header 2
public static boolean interrupted
現在のスレッドが中断されているかどうかをテストします.スレッドの割り込みステータスは、このメソッドによって消去されます.すなわち、このメソッドが2回連続して呼び出されると、2回目の呼び出しはfalseに戻る(1回目の呼び出しがブレーク状態をクリアした後、2回目の呼び出しがブレーク状態を検証する前に、現在のスレッドが再び中断した場合を除く).
public boolean isInterrupted()
スレッドが中断されたかどうかをテストします.スレッドの割り込み状態はこのメソッドの影響を受けません.
public void interrupt()
スレッドを中断します.
Thread.interruptメソッドは、スレッドが実行中のInterruptedExceptionを投げ出すメソッドを中断することができます.interruptメソッドを実行すると、そのスレッドは異常を投げ出し、次の例のような異常な方法でスレッドを中断します.

例1

public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(60);
                } catch (InterruptedException e) {
                    // 
                    System.err.println("this thread has been notified...");
                }

            }
        });
        thread.start();
        // thread 
        TimeUnit.SECONDS.sleep(1);
        thread.interrupt();
        System.out.println("finish");
    }

sleepメソッドはInterruptedExceptionを放出し、sleepメソッドは中断可能なメソッドであり、上記の例threadスレッドがsleep状態にある場合、mianスレッドはinterruptメソッドを呼び出して睡眠中のスレッドを中断する.catchでは必ずリソースのクリーンアップを行います.interrupt()メソッドでは、ロック待ちまたはI/O待ちのスレッドを中断することはできない.I/O待ちのリソースをオフにする場合は、下位のリソースを直接オフにしてスレッドを終了することができるが、ロック待ちのスレッドの終了は以下の例である.この例では特に、InterruptedException異常がキャプチャされると、割り込み状態がfalseにリセットされることに注意してください.

例2


Java割り込みメカニズムは,割り込みによって別のスレッドを直接終了することはできず,割り込まれたスレッドが自分で割り込みを処理する必要があるというコラボレーションメカニズムである.次の例では,スレッドを中断するためにThreadクラスのフラグ変数の方法を検討する.
class Compute implements Runnable {

    @Override
    public void run() {
        double d = 1.0;

        while (!Thread.interrupted()) {

            d = d + (Math.PI + Math.E) / d;

        }
    }
}

public class NonInterrupTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Compute());
        thread.start();
        TimeUnit.SECONDS.sleep(2);
        thread.interrupt();
        System.out.println("interrupt...");
    }
}

上記の点を強調しますinterrupted()メソッドは呼び出し後にThreadのフラグ変数がリセットされます

ReentrantLock


ロック待機中のスレッドについては、Threadを通過できません.interruptメソッドはすぐにスレッドを中断しますが、interruptによってロック待ちを中断できるロックはありますか?実際にはlockInterruptibly法で実現できます

class BlockMutex {
    private Lock lock = new ReentrantLock();

    public BlockMutex() {
        lock.lock();
    }

    public void f() {
        try {
            lock.lockInterruptibly();
            System.out.println("lock acquire in f() ");
        } catch (InterruptedException e) {
            // 
            e.printStackTrace();
        }
    }

}

class MyBlockThread implements Runnable {

    private BlockMutex blockMutex;

    public MyBlockThread(BlockMutex blockMutex) {
        this.blockMutex = blockMutex;
    }

    @Override
    public void run() {
        System.out.println("waiting lock in f()");
        blockMutex.f();
        System.out.println("broken out of blocked call");
    }
}

public class MyLockInterruptTest {
    public static void main(String[] args) throws InterruptedException {
        // BlockThread blockMutex 
        BlockMutex blockMutex = new BlockMutex();
        Thread thread = new Thread(new MyBlockThread(blockMutex));
        thread.start();
        TimeUnit.SECONDS.sleep(1);
        // 
        thread.interrupt();
    }
}

プライマリ・スレッドは、BlockMutexの作成時にオブジェクト・ロックを保持し、別のスレッドはBlockMutexオブジェクト・ロックの取得を待つと中断します.