1. ホーム

[解決済み】Java 8のインターフェースメソッドで "synchronized "が使えない理由は?

2022-04-08 05:20:49

質問

Java 8では、簡単に書くことができます。

interface Interface1 {
    default void method1() {
        synchronized (this) {
            // Something
        }
    }

    static void method2() {
        synchronized (Interface1.class) {
            // Something
        }
    }
}

クラスで使用できる完全な同期セマンティクスを得ることができます。しかし、私は synchronized モディファイアをメソッド宣言に使用します。

interface Interface2 {
    default synchronized void method1() {
        //  ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
    }

    static synchronized void method2() {
        // ^^^^^^^^^^^^ Modifier 'synchronized' not allowed here
    }
}

さて、この2つのインターフェイスの動作は Interface2 を確立します。 契約 について method1()method2() よりも少し強いです。 Interface1 のようになります。もちろん、次のように主張することもできます。 default の実装は、具体的な実装の状態についていかなる仮定もするべきではないし、そのようなキーワードは単にその重みを引き出さないだろう。

質問です。

JSR-335エキスパートグループが synchronized をインターフェイスメソッドに追加することはできますか?

どのように解決するのですか?

をサポートすることは、一見、当然のことのように思えます。 synchronized という修飾子をデフォルトのメソッドにつけることは危険であることがわかり、禁止されました。

同期されたメソッドとは、あたかも本体全体が synchronized ブロックのロックオブジェクトがレシーバーとなります。 このセマンティクスをデフォルト・メソッドにも拡張することは賢明と思われるかもしれません。 (結局のところ、彼らもレシーバーを持つインスタンス・メソッドなのです(ただし synchronized メソッドは、完全に構文的な最適化であり、必要なものではなく、対応する synchronized ブロックがあります。 そもそも構文の最適化が時期尚早であり、同期されたメソッドは解決するよりも多くの問題を引き起こすという合理的な議論がありますが、その船はずっと前に出航しています)。

では、なぜ危険なのでしょうか? 同期とは、ロックすることです。 ロックとは、変更可能な状態への共有アクセスを調整することです。 各オブジェクトは、どのロックがどの状態変数を保護するかを決定する同期化ポリシーを持っている必要があります。 (参照 Java並行処理の実際 2.4節参照)

多くのオブジェクトは、同期化ポリシーとして Java Monitorパターン (JCiP 4.1) では、オブジェクトの状態はその固有ロックによって保護されます。 このパターンには何のマジックも特別なものもありませんが、便利です。 synchronized キーワードは、暗黙のうちにこのパターンを想定しています。

そのオブジェクトの同期ポリシーを決定するのは、その状態を所有するクラスなのです。 しかし、インターフェースは、それが混在しているオブジェクトの状態を所有しません。 ですから、インターフェイスの中で同期化されたメソッドを使うことは、特定の同期化ポリシーを仮定することになりますが、それはあなたが仮定するための合理的な根拠がないため、同期化の使用は何の追加スレッド安全性を提供しない(間違ったロックで同期化しているかもしれない)ということになるかもしれません。 この場合、スレッドセーフについて何かをしたという誤った確信を持つことになり、エラーメッセージも間違った同期ポリシーを仮定していることを教えてくれません。

単一のソースファイルに対して同期ポリシーを一貫して維持することは既に十分困難です。サブクラスがそのスーパークラスによって定義された同期ポリシーを正しく遵守することはさらに困難です。 このような疎結合のクラス(インターフェイスとそれを実装する多くのクラス)の間で同期を行おうとすると、ほとんど不可能であり、非常にエラーを起こしやすいでしょう。

これらの反対論があるとして、賛成論は何だろう? ほとんどの場合、インターフェイスをより特質に近い形で動作させることを目的としているようです。 これは理解できる願望ですが、デフォルトメソッドの設計の中心はインターフェイスの進化であって、"Trait--"ではないのです。 この2つが一貫して達成できるところでは、そうするように努めましたが、一方が他方と対立するところでは、主要な設計目標を優先して選択しなければなりませんでした。