web-dev-qa-db-ja.com

抽象メソッドを同期できないのはなぜですか?

CodeRanchのスレッド を読んでいたところ、抽象クラスをインスタンス化できないため、抽象メソッドを同期できなかった、つまりロックするオブジェクトがないと言っていました。

抽象クラスは子クラスの定義(コントラクト)であるため、これは意味がありません。同期メソッドの抽象定義はロックする必要はありませんが、子はロックします。すべての抽象的な見出しは、子供が しなければならない このメソッドを同期します。これに関する私の論理は正しいですか?そうでない場合、誰かが私が間違っている理由を説明できますか?

26
ahodder

抽象クラスをインスタンス化できないというコメントはごみです。抽象化するにはインスタンスメソッドでなければならないことを考えると、確かにisロックされる可能性のある参照があります。抽象クラスの具象メソッドは、引き続きthisを参照できます。ただし、それでも抽象クラスを同期できる必要があるという意味ではありません。

メソッドが同期されるかどうかは、メソッドの実装の詳細です。同期は指定されていませんどこでも宣言型コントラクトとして-インターフェイスでも同期できるわけではありません。

クラスが提供するスレッドセーフ保証をどのように実装するかは、クラス次第です。抽象クラスが特定のアプローチをmandateしたい場合は、テンプレートメソッドパターンを使用する必要があります。

// I hate synchronizing on "this"
private final Object lock = new Object();

public final void foo() {
    synchronized(lock) {
        fooImpl();
    }
}

protected abstract void fooImpl();

ただし、デッドロックなどのレシピであるロック内の「不明な」コードを効果的に呼び出していることを考えると、それ自体はかなり危険です。

32
Jon Skeet

申し訳ありませんが、それは意味がありません、それはそれがどのように機能するかです。ロック動作は、抽象メソッドまたはインターフェースメソッドを使用して指定することはできません。これはコントラクトの一部ではありません。おそらく、ロック動作は基本的に実装の一部であり、実装が異なればロックも異なる方法で実行する必要があり、その抽象化レベルでロックを指定するのは行き過ぎだという考えでした。

8
Nathan Hughes
synchronized void foo()
{
    body
}

と同等であると定義されています

void foo()
{ 
    synchronized(this)
    {
        body
    }
}

(静的な場合、thisの代わりにクラスで同期されます)

抽象メソッドには本体がないため、メソッドのsynchronizedキーワードは未定義です。

4
irreputable

その背後にあるロジックの1つは、そのメソッドを同期するかどうかを実装クラスが決定する必要があるということだと思います。つまり、同期実装と非同期実装のどちらを提供するかを実装者が自由に選択できるようになります。さらに、クライアントには、スレッドセーフが問題にならない場合に同期のオーバーヘッドを回避するために、同期されていないバージョンを選択するオプションもあります。

3
Bhesh Gurung