Javaコンカレント:第2部-マルチスレッド

7781 ワード

スレッドの作成方法について説明した後、この記事では、マルチスレッドについて何ができるかについて説明します.
スレッドがあれば、スレッドに対して次のような操作を行うことができます.
1、現在のスレッドをxミリ秒の時間内に睡眠させる.
2、1つの他のスレッドが終わるのを待つ.
3、スレッドの優先度を管理し、1つのスレッドを一時停止し、1つの他のスレッドに実行の機会を与える.
4、中断スレッド;
これらのことをどうすればいいか見てみましょう.
まず簡単に、指定された数のミリ秒以内に1つのスレッドをスリープさせることができます.この点を達成するために、Threadクラスにはsleep(long millis)という方法があります.しかし、この方法は静的なので、現在のスレッドを睡眠状態にするしかありません.睡眠を望んでいるスレッドを選択することはできません.あなたの唯一の選択は現在のスレッドです.
Thread.sleep(1000);
現在のスレッドを1000ミリ秒(つまり1秒)睡眠させます.しかし、異常をキャプチャする必要があります.InterruptedException.睡眠のスレッドが中断されると、この異常が発生します.このようにすることができます.
try {
	Thread.sleep(1000);
} catch (InterruptedException e){
	e.printStackTrace();
}
しかし、これは異常を管理する良い方法ではありません.後で、この異常をどのように処理するかを見ます.
より正確にするには、sleep()メソッドのリロードバージョンを使用して、2つのパラメータミリ秒とナノ秒のsleep()メソッドを使用します.この睡眠時間の精度はシステムクロックとタイマーに依存する.
例えば、1000ミリ秒1000ナノ秒の睡眠を望む場合は、次のようにすることができます.
try {
	Thread.sleep(1000, 1000);
} catch (InterruptedException e){
	e.printStackTrace();
}
上記のコードをテストする小さな例があります.
public class SleepThread {
    public static void main(String[] args) {
        System.out.println("Current time millis : " + System.currentTimeMillis());

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Current time millis : " + System.currentTimeMillis());

        System.out.println("Nano time : " + System.nanoTime());

        try {
            Thread.sleep(2, 5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Nano time : " + System.nanoTime());
    }
}
私のパソコンでは、上記のコードの実行結果は次のとおりです.
Current time millis : 1273959308480
Current time millis : 1273959309480
Nano time : 5878165216075
Nano time : 5878166730976

ミリ秒ベースの睡眠時間は非常に正確であるが、ナノ秒ベースの睡眠時間は粗いことが多い.もちろん、実行結果はあなたのパソコン、あなたのオペレーティングシステム、およびあなたの構成に依存します.一方、スレッドの中で他のスレッドの死を待つことができます.たとえば、5つのスレッドを作成して各セクションの結果を計算し、5つのスレッドが完了すると、5つのスレッドの結果に基づいて最終的な結果を計算できます.これにより、スレッドクラスのjoin()メソッドを使用できます.この方法は静的ではないので、任意のスレッドで死を待つことができます.スレッドが別のスレッドの割り込みを待っている場合、sleep()という方法ではInterruptedException異常が放出されます.スレッド2を待つためには、次のようにしなければなりません.
try {
	thread2.join();
} catch (InterruptedException e){
	e.printStackTrace();
}

これにより、現在のスレッドはthread 2の死を待たせる.タイムアウト時間を増やしたり、join()、join(long millis)、join(long millis、int nanos)メソッドのリロードバージョンを使用したりして、ミリ秒、またはミリ秒+ナノ秒単位で、すべての使い方を示す小さな例があります.
public class JoinThread {
	public static void main(String[] args) {
		Thread thread2 = new Thread(new WaitRunnable());
		Thread thread3 = new Thread(new WaitRunnable());

		System.out.println("Current time millis : " + System.currentTimeMillis());

		thread2.start();

		try {
			thread2.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("Current time millis : " + System.currentTimeMillis());

		thread3.start();

		try {
			thread3.join(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("Current time millis : " + System.currentTimeMillis());
	}

	private static class WaitRunnable implements Runnable {
		@Override
		public void run() {
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
        }
}
以上のコードが私のパソコンで実行された結果は以下の通りです.
Current time millis : 1274015478535
Current time millis : 1274015483538
Current time millis : 1274015484538

1番目のjoin()が別のスレッドを5秒間待っているのが見えます.私たちが1つのスーパーを設定したとき、私たちは1秒だけ待ってjoinメソッドから戻りました.スレッドを使用する場合も、スレッドの優先度を変更する可能性があります.Java仮想マシンでは、Threadクラスは優先度ベースのスケジューリングアルゴリズムを使用します.したがって、1つのスレッドがより高い優先度で実行状態に入ると、新しいスレッドが実行され、現在実行中のスレッドは実行可能状態に戻り、次回の実行を待機します.しかし、このような行為は保証できません.それはあなたが使用している仮想マシンに完全に依存しています.したがって、スレッドの優先度に依存せず、プログラムのパフォーマンスを向上させるためにのみ使用します.通常、スレッドクラスの優先度は0から10の整数ですが、一部の仮想マシンではより低いまたはより高い優先度を持っています.優先度の範囲を理解するには、スレッドクラスの定数を使用します.
public class ThreadPriorityRange {
	public static void main(String[] args) {
		System.out.println("Minimal priority : " + Thread.MIN_PRIORITY);
		System.out.println("Maximal priority : " + Thread.MAX_PRIORITY);
		System.out.println("Norm priority : " + Thread.NORM_PRIORITY);
         }
}
私の機械では、私はいつも次のような結果を得ています.
Minimal priority : 1
Maximal priority : 10
Norm priority
スレッドの優先度を設定する場合は、ThreadクラスのsetPriority(int priority)メソッドを使用します.最大優先度よりも大きな値を入力すると、この方法では最大優先度に対応する値が使用されます.優先度を指定しない場合は、現在のスレッドの優先度がデフォルトで使用されます.
もう1つの優先度に関連する方法はyield()方法であり、この方法は静的であるため、現在のスレッドに作用する.この方法の役割は、スレッドを再び実行状態にすることであり、他のスレッドは再び実行の機会を待つしかない.しかし、実践では、この方法の行為は保証できない.特定のシステムでは、1つの空の操作として実現できます.実際にこれをテストするのは容易ではありません.その実行結果は本当にあなたのパソコン、仮想マシン、オペレーティングシステムに依存しているからです.実際にはスレッドの優先度を使用しないほうがいいです.
最後にスレッドクラスを使用してできることは、それを中断することです.Javaでは、1つのスレッドが終了していない場合、停止を強制することはできません.無限の実行を続けます.しかし、Threadクラスのinterrupt()メソッドを使用して中断することができます.この方法は1つのスレッドを中断し,スレッドが寝ているか別のスレッドに参加している場合,1つのInterruptedExceptionを投げ出す.スレッドが寝ているか、別のスレッドに追加されている場合、スレッドの割り込み状態がクリアされることを知っておく必要があります.名前の通りisInterrupted()メソッドはfalseを返します.次の例を示します.
public class InterruptThread {
	public static void main(String[] args) {
		Thread thread1 = new Thread(new WaitRunnable());

		thread1.start();

		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		thread1.interrupt();
	}

	private static class WaitRunnable implements Runnable {
		@Override
		public void run() {
			System.out.println("Current time millis : " + System.currentTimeMillis());

			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				System.out.println("The thread has been interrupted");
				System.out.println("The thread is interrupted : " + Thread.currentThread().isInterrupted());
			}

			System.out.println("Current time millis : " + System.currentTimeMillis());
		}
        }
}
が実行されると、次のような結果が得られます.
Current time millis : 1274017633151
The thread has been interrupted
The thread is interrupted : false
Current time millis : 1274017634151
秒後、2番目のスレッドが中断され、その中断状態がfalseに設定されていることがわかります.もしあなたが睡眠を取っていないならば、しかし多くの重い仕事をして、あなたは下のように中断をテストして、あなたのスレッドの正しい中断を促すことができます.
public class InterruptableRunnable implements Runnable {
	@Override
	public void run() {
		while(!Thread.currentThread().isInterrupted()){
			//Heavy operation
		}
	}
}
スレッドを中断する方法を知っています.このような簡単なキャプチャInterruptedExceptionは、スレッドを「安全に中断」するのに十分ではありません.あなたのスレッドを想像してみてください.
public class UglyRunnable implements Runnable {
	@Override
	public void run() {
		while(!Thread.currentThread().isInterrupted()){
			//Heavy operation
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//Other operation
		}
	}
}
現在、スレッドが眠っている間に、別のスレッドがスレッドを中断したいと思っています.睡眠は中断されますが、中断状態はクリアされ、サイクルが継続できるようになります.より良いスレッドを作成する方法は、InterruptedException例外をキャプチャした後、スレッドを再中断することです.
public class BetterRunnable implements Runnable {
	@Override
	public void run() {
		while(!Thread.currentThread().isInterrupted()){
			//Heavy operation
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				Thread.currentThread().interrupt();
			}
			//Other operation
		}
	}
}

このコードを使用すると、割り込み後に割り込み状態が回復し、ループが停止します.あなたのコードに基づいて、中断した後、interrupt()メソッドの後にcontinue文を追加して、操作しないことを確認することもできます.場合によっては、いくつかのif文を使用して割り込み状態を検出し、何かを制御したりしない必要があります.だから、スレッドでできることはすべて知っています.この文章が面白いと思ってほしい.ここで本明細書のソースコードをダウンロードできます.次の記事では、Javaの同時実行について、スレッドのセキュリティを保証するために同期コードを使用する方法について説明します.
本文の英文の原文:http://www.baptiste-wicht.com/2010/05/java-concurrency-part-2-manipulate-threads/