5

重複の可能性:
同期ブロック vs 同期メソッド?

同期されたメソッドと同期されたオブジェクトの違いについて、誰かが実際の例で私を助けることができれば、それはいいでしょう.

メソッド同期の例

public class MyClassExample {
private int i;
public synchronized void increment(){
    i = i + 1;
}
}

オブジェクト同期の例

public class MyClassExample {
private int i;
Object writeLock = new Object();
 public void increment(){
    synchronized(writeLock) {
        i = i + 1;
    }
}
}
4

3 に答える 3

11

tl; dr-外部同期により、攻撃(意図的またはその他)が発生する可能性があります。また、不要な可能性のあるチェックをロックするように強制されます。また、この回答の一番下にオタクの良い情報があります。

同期された方法は、これで同期することとほとんど同じです(下を参照)。

synchroinzed void foo() {

}

void foo() {
    synchronized(this) {

    }
}

メソッド自体をではなくすることで、だけでなく、synchronized任意のをロックできるようになります。私は個人的に、そのように、内部で同期することをお勧めしますObjectthisObject

private final Object foolock = new Object();

void foo() {
    synchronzied(foolock) {

    }
}

その理由は、他の誰かがあなたsynchronizedを効果的にロックし、あなたをあなたから締め出す方法を実行した場合です!次のことを想像してみてください。thissynchronizeObject

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つであるため、これは小さな影響を与える可能性があります。この細かな点にもかかわらず、これはマイクロ最適化であり、本番環境ではそれほど重要ではないため、同じように扱うことを強くお勧めします。彼らがそうでないとき、それを同一と呼ぶことは完全ではないでしょう。

于 2012-09-12T23:46:10.843 に答える
3

synchronizedインスタンス メソッドは で同期しますthis

そう

public synchronized void increment(){
    i = i + 1;
}

と同等です

public void increment(){
    synchronized (this) {
        i = i + 1;
    }
}
于 2012-09-12T23:35:48.647 に答える
2

Java 言語仕様には次のように書かれています。

同期メソッドは、実行前にモニター (§17.1) を取得します。

クラス (静的) メソッドの場合、メソッドのクラスの Class オブジェクトに関連付けられたモニターが使用されます。

thisインスタンス メソッドの場合、 (メソッドが呼び出されたオブジェクト) に関連付けられたモニターが使用されます。

これらは、同期ステートメント (§14.19) で使用できる同じモニターです。

したがって、コードは次のとおりです。

class Test {
    int count;
    synchronized void bump() {
        count++;
    }
    static int classCount;
    static synchronized void classBump() {
        classCount++;
    }
}

以下とまったく同じ効果があります。

class BumpTest {
    int count;
    void bump() {
        synchronized (this) { count++; }
    }
    static int classCount;
    static void classBump() {
        try {
            synchronized (Class.forName("BumpTest")) {
                classCount++;
            }
        } catch (ClassNotFoundException e) {}
    }
}
于 2012-09-12T23:37:44.457 に答える