tl; dr-外部同期により、攻撃(意図的またはその他)が発生する可能性があります。また、不要な可能性のあるチェックをロックするように強制されます。また、この回答の一番下にオタクの良い情報があります。
同期された方法は、これで同期することとほとんど同じです(下を参照)。
synchroinzed void foo() {
}
void foo() {
synchronized(this) {
}
}
メソッド自体をではなくすることで、だけでなく、synchronized
任意のをロックできるようになります。私は個人的に、そのように、内部で同期することをお勧めしますObject
this
Object
private final Object foolock = new Object();
void foo() {
synchronzied(foolock) {
}
}
その理由は、他の誰かがあなたsynchronized
を効果的にロックし、あなたをあなたから締め出す方法を実行した場合です!次のことを想像してみてください。this
synchronize
Object
class FooDoer {
// removed! using synchronized methods instead
//final Object foolock = new Object();
synchronized void foo() {
}
}
// thread 1 - attacker
FooDoer f = new FooDoer();
globalMap.put("TheFoo",f);
synchronized(f) {
while(true); // haha!
}
// thread 2 - victim
FooDoer f = globalMap.get("TheFoo");
f.foo(); // locked, because Thread 1 has locked us out!
これにより、サービス拒否攻撃が発生する可能性があります。それは良いことではありません!ロックを内部にすることで、クラスの作成者は、オブジェクトのどの領域をどの条件でロックできるかを正確に制御できます。
もう1つの問題は、チェック用に保護されたデータがない可能性があることです。例えば:
synchronized void foo() {
if(expensiveAccessCheck()) {
update();
}
}
void foo() {
if(expensiveAccessCheck()) {
synchronized(foolock) {
update();
}
}
}
このシナリオでは、車輪を回しながらそこに座っている間、他の全員を待たせる必要はありません。おそらく、URLからデータをスクレイピングしてから更新しているのでしょう。なぜ他のすべての人をデータから締め出しておくのですか?この場合、粒度は低いほど優れています。
今、あなたは私が以前にほとんど同じと言ったことを思い出すかもしれません。2つの間には小さな、小さな、小さな違いがあります。同期されたメソッドは、バイトコードのメソッドシグネチャに直接同期するように命令をベイク処理します。これにより、余分な呼び出しを行う必要がないため、バイトコードが1バイト短くなります。メソッドのバイトコードのバイト数は、インラインにするかどうかを決定する要因の1つであるため、これは小さな影響を与える可能性があります。この細かな点にもかかわらず、これはマイクロ最適化であり、本番環境ではそれほど重要ではないため、同じように扱うことを強くお勧めします。彼らがそうでないとき、それを同一と呼ぶことは完全ではないでしょう。