ABC----javaマルチスレッドの古典的な面接問題を順番に印刷します

3548 ワード

これは迅雷の面接問題で、ABCを10回順番に印刷します.
ソースコードは次のとおりです.
public class PrintABC {

	public static Boolean isThreadA = true;
	public static Boolean isThreadB = false;
	public static Boolean isThreadC = false;

	public static void main(String[] args) {
		final PrintABC abc = new PrintABC();
		new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i < 10; i++) {
					synchronized (abc) {
						while(!isThreadA) {
							try {
								abc.wait();
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
							System.out.print("A");
							isThreadA = false;
							isThreadB = true;
							isThreadC = false;
							abc.notifyAll();
					}
				}
			}
		}).start();

		new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i < 10; i++) {
					synchronized (abc) {
						while(!isThreadB) {
							try {
								abc.wait();
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
							System.out.print("B");
							isThreadA = false;
							isThreadB = false;
							isThreadC = true;
							abc.notifyAll();
					}
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i < 10; i++) {
					synchronized (abc) {
						while(!isThreadC) {
							try {
								abc.wait();
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
							System.out.print("C");
							isThreadA = true;
							isThreadB = false;
							isThreadC = false;
							abc.notifyAll();
					}
				}
			}
		}).start();
	}
}

出力結果は以下の通り:ABCABCABCABCABC
構想:解題構想は大体このようにして、3つのスレッドを開いて、各スレッドは一度に1つのアルファベットを印刷して、しかも一定の順序で印刷して、Aを印刷する時、他のスレッドはブロック状態にあって、Aを印刷し終わった後、スレッドをロックして、Bを印刷するそのスレッドを開いて、他のスレッドはブロック状態にあって、同じようにCを印刷する時、他のスレッドをブロックして、この3つのスレッドを順次ループすることで,ABCを順次複数回印刷する目的が達成される.
この問題は考え方が簡単そうに見えますが、主にwait()方法とnotify()方法、キーワードsynchronizedを使う必要があります.これらを十分に理解してこそ、この問題を解くことができます.次はこの2つの方法とキーワードsynchronizedについて説明する必要があります.
JAVAでは,PV操作,プロセス反発などに関する手法はない.JAVAのプロセス同期はsynchronized()によって実現されるが、説明が必要なのは、JAVAのsynchronized()メソッドはオペレーティングシステムの概念における反発メモリブロックに類似しており、JAVAにおけるObjectタイプではいずれも1つのメモリロックを有しており、スレッドがこのメモリロックを取得した後、他のスレッドはそのメモリにアクセスできず、JAVAにおける簡単な同期・反発操作を実現する.この原理を理解すれば、synchronized(this)とsynchronized(static XXX)の違いが理解できます.synchronizedはメモリブロックに対してメモリロックを申請します.thisキーワードはクラスのオブジェクトを表します.そのメモリロックは同じオブジェクトに対する反発動作ですが、staticメンバーはクラス固有で、そのメモリ空間はクラスのすべてのメンバーに共有されています.これによりsynchronized()はstaticメンバーにロックをかけ、クラスにロックをかけることに相当します.つまり、クラスのすべてのメンバー間で反発を実現し、同じ時間にクラスのインスタンスにアクセスできるスレッドは1つしかありません.JAVAでのスレッド反発を簡単に実現したいだけなら、これらの基本を理解すれば十分です.しかし、ライン間の相互起動が必要な場合はObjectを借りる必要がある.wait(), Object.nofity()です.
    Obj.wait()とObj.notify()はsynchronized(Obj)とともに使用する必要がある、すなわちwaitであり、notifyとはすでにObjロックが取得する操作であり、文法的にはObjである.wait(),Obj.notifyはsynchronized(Obj){...}文ブロック内.機能的にwaitとは,スレッドがオブジェクトロックを取得した後,オブジェクトロックをアクティブに解放し,同時に本スレッドがスリープすることである.他のスレッド呼び出しオブジェクトのnotify()がスレッドを起動するまで、オブジェクトロックを取得し、実行を続行しません.対応するnotify()は、オブジェクトロックの起動操作です.ただし、notify()呼び出し後、すぐにオブジェクトロックを解除するのではなく、対応するsynchronized(){}文ブロックで実行が終了し、自動的にロックを解除すると、JVMはwait()オブジェクトロックのスレッドからランダムにスレッドを選択し、オブジェクトロックを付与し、スレッドを起動し、実行を継続することに注意してください.これにより、オンライン・スレッド間の同期、起動の操作が提供されます.Thread.sleep()とObject.wait()両方とも現在のスレッドを一時停止するCPU制御権を解放することができ、主な違いはObjectである.wait()は、CPUを解放するとともに、オブジェクトロックの制御を解放する.これらを理解してこの面接問題を解決すれば問題にならないはずです.