私はいくつかの共有変数 x、y、z を持っています。それらはすべて、2 つの異なるスレッドで実行されている 2 つの異なるメソッドで変更できます (スレッド 1 のメソッド 1 とスレッド 2 のメソッド 2 など)。これら 2 つのメソッドを synchronized として宣言すると、変数 x、y、z の一貫性が保証されますか。それとも、これらの変数ごとに個別にロックを使用する必要がありますか?
4 に答える
はい、これらの変数がすべてプライベートであり、2 つの同期メソッドの外部でアクセス (読み取りまたは書き込み) されないと仮定すると、アプローチは一貫性を保証します。
同期ブロックの外でこれらの変数を読み取ると、一貫性のない結果が得られる可能性があることに注意してください。
class Foo {
private int x;
public synchronized void foo() {
x = 1;
}
public synchronized void bar() {
x = 2;
}
public boolean baz() {
int a = x;
int b = x;
// Unsafe! x could have been modified by another thread between the two reads
// That means this method could sometimes return false
return a == b;
}
}
編集:静的変数に関するコメントに対処するために更新されました。
各クラスは独自のデータを所有する必要があります。クラスA
が (パブリックにすることによって) 変数への直接アクセスを許可する場合、それは独自のデータを所有していないため、スレッド セーフを適用することが非常に困難になります。
これを行う場合:
class A {
private static int whatever;
public static synchronized int getWhatever() {
return whatever;
}
public static synchronized void setWhatever(int newWhatever) {
whatever = newWhatever;
}
}
それなら大丈夫です。
synchronized
単一のオブジェクトにミューテックスを適用することを思い出してください。同期されたメソッドの場合this
は (または静的メソッドの場合は Class オブジェクト) です。他のオブジェクトの同期ブロックは干渉しません。
class A {
public synchronized void doSomething() {...}
}
class B {
public synchronized void doSomethingElse() {...}
}
の呼び出しは、別のオブジェクトで同期されているため、doSomething
の呼び出しを待機しません。この場合、 の関連するインスタンスと の関連するインスタンスです。同様に、 の異なるインスタンスに対する の2 つの呼び出しは干渉しません。doSomethingElse
A
B
doSomething
A
Java Concurrency in Practiceをご覧になることを強くお勧めします。Java スレッドとメモリー・モデルの微妙な点をすべて説明した優れた本です。
はい、一貫性があります。
同期メソッドは、実行前にモニター (§17.1) を取得します。クラス (静的) メソッドの場合、メソッドのクラスの Class オブジェクトに関連付けられたモニターが使用されます。インスタンス メソッドの場合、これ (メソッドが呼び出されたオブジェクト) に関連付けられたモニターが使用されます。
このリンクをチェックしてください
注:- 注意しなければならない点の 1 つは (通常、数人のプログラマーがその罠に陥ります)、同期された静的メソッドと同期された非静的メソッドの間にリンクがないことです。
メソッドで同期する場合:
- method が の場合、オブジェクト
static
のロックが取得されますclass
- method が の場合
non-static
、オブジェクトはロックされinstance
ます。
一度に 1 つのスレッドだけがロックを取得する限り、一貫性があり、意図したことを安全に行うことができます。
これは主観的です。動作は、スレッドをインスタンス化する方法によって異なります。2 つのスレッドが、これらのメソッドを含むクラスの同じインスタンスで同期化されたメソッドを呼び出すと、ブロックされます。各スレッドがメソッドを含むクラスの新しいオブジェクトをインスタンス化する場合、クラスの 2 つの異なるインスタンスに 2 つのロックがあるため、スレッドはブロックされません。