クラス ロックとオブジェクト ロックは競合しますか?オブジェクト ロックとプライベート ロックは競合しますか?例を通して説明します。
1. 関連協定
以下の説明を明確にするために、まず、この記事に含まれるロックの関連定義に関して次の規則を作成します。
1. クラス ロック: コード内のメソッド、または以下の increamment() などの同期 (xxx.class) コード セグメントに静的ロックと同期ロックを追加します。
2. オブジェクト ロック: コード内のメソッド、または以下の synOnMethod() や synInMethod() などの同期 (この) コード セグメントに同期ロックを追加します。
3. プライベート ロック: クラス内でプライベート オブジェクト ロックなどのプライベート プロパティを宣言し、ロックする必要があるコード セグメント (以下の synMethodWithObj() など) を同期 (ロック) します。
2. テストコード
1. スタートアップ クラス ObjectLock を作成します。
次のようにコードをコピーします。
パブリック クラス ObjectLock {
public static void main(String[] args) {
System.out.println("開始時間 = " + System.currentTimeMillis()+"ms");
LockTestClass テスト = new LockTestClass();
for (int i = 0; i < 3; i++) {
スレッド thread = new ObjThread(test, i);
thread.start();
}
}
}
2. 同期メソッドを開始するスレッド クラス ObjThread を記述します (その実行メソッドはさまざまなテストに合わせて調整される可能性があることに注意してください)
次のようにコードをコピーします。
public class ObjThread extends Thread {
LockTestClass ロック。
int i = 0;
public ObjThread(LockTestClass lock, int i) {
this.lock = ロック;
this.i = i;
}
public void run() {
//ロックレスメソッド
//lock.noSynMethod(this.getId(),this);
//オブジェクト ロック メソッド 1、同期された synInMethod を使用
lock.synInMethod();
//オブジェクトロック方法2、synchronized(this)メソッドを使用
//lock.synOnMethod();
//プライベートロックメソッド、synchronized(object)メソッドを使用
//lock.synMethodWithObj();
//クラスロック方式、静的同期インクリメント方式を使用
LockTestClass.increment();
}
}
3. さまざまなロック メソッドを含む、別のロック テスト クラス LockTestClass を作成します。
次のようにコードをコピーします。
パブリック クラス LockTestClass {
//クラスロックのカウントに使用されます
プライベート静的 int i = 0;
//プライベートロック
プライベート オブジェクト object = new Object();
/**
* <p>
※ロックフリー方式
*
* @paramスレッドID
* @param スレッド
*/
public void noSynMethod(long threadID, ObjThread thread) {
System.out.println("nosyn: クラス obj は " + thread + "、threadId は"
+ スレッド ID);
}
/**
※オブジェクトロック方法1
*/
public synchronized void synOnMethod() {
System.out.println("synOnMethod の開始" + ", time = "
+ System.currentTimeMillis() + "ミリ秒");
試す {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synOnMethod が終了します");
}
/**
* オブジェクトのロック方法 2、同期 (this) を使用してロックする
*/
public void synInMethod() {
同期された (これ) {
System.out.println("synInMethod の開始" + ", time = "
+ System.currentTimeMillis() + "ミリ秒");
試す {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synInMethod が終了します");
}
}
/**
※オブジェクトロック方法3
*/
public void synMethodWithObj() {
同期された (オブジェクト) {
System.out.println("synMethodWithObj が始まります" + ", time = "
+ System.currentTimeMillis() + "ミリ秒");
試す {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synMethodWithObj が終了する");
}
}
/**
* クラスロック
*/
public static synchronized void increamment() {
System.out.println("クラスが同期されました。i = " + i + ", time = "
+ System.currentTimeMillis() + "ミリ秒");
i++;
試す {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("クラスの同期が終了しました。");
}
}
3. 試験結果
1. クラス ロックとオブジェクト ロックをテストするには、ObjectThread の run メソッドを次のように変更します。
次のようにコードをコピーします。
public void run() {
//ロックレスメソッド
//lock.noSynMethod(this.getId(),this);
//オブジェクト ロック メソッド 1、同期された synInMethod を使用
lock.synInMethod();
//オブジェクトロック方法2、synchronized(this)メソッドを使用
//lock.synOnMethod();
//プライベートロックメソッド、synchronized(object)メソッドを使用
//lock.synMethodWithObj();
//クラスロック方式、静的同期インクリメント方式を使用
LockTestClass.increamment();
}
端子出力:
次のようにコードをコピーします。
開始時間 = 1413101360231ms
synInMethod の開始、時間 = 1413101360233ms
synInMethod が終了する
クラスは同期されています。i = 0、時間 = 1413101362233ms
synInMethod の開始、時間 = 1413101362233ms
クラス同期が終了します。
synInMethod が終了する
クラスは同期されています。i = 1、時間 = 1413101364233ms
synInMethod の開始、時間 = 1413101364233ms
クラス同期が終了します。
synInMethod が終了する
クラスは同期されています。i = 2、時間 = 1413101366234ms
クラス同期が終了します。
オブジェクト ロック メソッド (synInMothod) は、最初の起動時にクラス ロック メソッド (increamment) よりも 2 秒速いことがわかります。これは、synInMehtod の実行時に 2 秒間スリープしてから increamment が実行されるためです。メソッドは同じスレッドを共有するため、実行時に increamment が synInMethod の前に配置されると、increamment が初めて開始されるときは 2 秒速くなります。
クラス ロック メソッドが開始されると、別のスレッドのオブジェクト ロック メソッドもほぼ同時に開始されます。これは、2 つが同じロックを使用していないことを示しており、競合は発生しません。
結論: クラス ロックとオブジェクト ロックは競合せず、それらのロック方法は相互に影響しません。
2. プライベート ロックとオブジェクト ロックでは、ObjectThread の run メソッドが次のように変更されます。
次のようにコードをコピーします。
public void run() {
//ロックレスメソッド
//lock.noSynMethod(this.getId(),this);
//オブジェクト ロック メソッド 1、同期された synInMethod を使用
lock.synInMethod();
//オブジェクトロック方法2、synchronized(this)メソッドを使用
//lock.synOnMethod();
//プライベートロックメソッド、synchronized(object)メソッドを使用
lock.synMethodWithObj();
//クラスロック方式、静的同期インクリメント方式を使用
//LockTestClass.increamment();
}
端子出力:
次のようにコードをコピーします。
開始時間 = 1413121912406ms
synInMethod が開始され、時間 = 1413121912407 ミリ秒です。
synInMethod が終了します。
synMethodWithObj が開始、時間 = 1413121914407ms
synInMethod が開始されます。時間 = 1413121914407 ミリ秒です。
synInMethod が終了します。
synMethodWithObj が終了する
synInMethod が開始されます。時間 = 1413121916407 ミリ秒です。
synMethodWithObj が開始され、時間 = 1413121916407ms
synInMethod が終了します。
synMethodWithObj が終了する
synMethodWithObj が開始、時間 = 1413121918407ms
synMethodWithObj が終了する
クラス ロックやオブジェクト ロックとよく似ています。
結論: プライベート ロックとオブジェクト ロックは競合せず、それらのロック方法は相互に影響しません。
3.Synchronizedをメソッドに直接追加してsynchronized(this)し、ObjectThreadのrunメソッドを以下のように修正します。
次のようにコードをコピーします。
public void run() {
//ロックレスメソッド
//lock.noSynMethod(this.getId(),this);
//オブジェクト ロック メソッド 1、同期された synInMethod を使用
lock.synInMethod();
//オブジェクトロック方法2、synchronized(this)メソッドを使用
lock.synOnMethod();
//プライベートロックメソッド、synchronized(object)メソッドを使用
//lock.synMethodWithObj();
//クラスロック方式、静的同期インクリメント方式を使用
//LockTestClass.increamment();
}
端子出力:
次のようにコードをコピーします。
開始時間 = 1413102913278ms
synInMethod の開始、時間 = 1413102913279ms
synInMethod が終了する
synInMethod の開始、時間 = 1413102915279ms
synInMethod が終了する
synOnMethod の開始、時間 = 1413102917279ms
synOnメソッドが終了します
synInMethod の開始、時間 = 1413102919279ms
synInMethod が終了する
synOnMethod の開始、時間 = 1413102921279ms
synOnメソッドが終了します
synOnMethod の開始、時間 = 1413102923279ms
synOnメソッドが終了します
ご覧のとおり、2 つの出力は厳密にシリアルに行われます (もちろん、再実行時に synInMethod と synOnMethod のどちらが最初に実行されるかは、ロックの取得者によって決まりません)。
結論: メソッドに直接追加された synchronized と synchronized(this) は両方とも現在のオブジェクトをロックします。2 つのロック メソッドは競合関係にあり、同時に実行できるメソッドは 1 つだけです。