6

インターフェイスには同期が必要なデフォルトのメソッドがいくつかありますが、次のメソッドしかthis利用できないようです:

default void addUniqueColumns(List<String> names) {
    synchronized (this) {
        ... do something
    }
}

this問題は、制御を強化するのではなく、プライベート ロックで同期したいということです。

default void addUniqueColumns(List<String> names) {
    synchronized (lock) {  // how to get a private lock in a default method??
        ... do something
    }
}

ソリューション?巧妙な回避策?または、それと一緒に暮らす:)!

4

3 に答える 3

2

ロック オブジェクトをパッケージ可視クラスの public static フィールドに配置して、すべての既定のメソッドでロックを共有できます。ロックはライブラリ内で表示されたままになりますが、デフォルトのアクセス権を持つクラスはライブラリ外では表示されないため、ロックはライブラリのインターフェイスのユーザーに対して非公開になります。

class LockHolder { // Package private class
    public static Object LOCK = new Object();
}

public interface ColumnCollection {
    default void addUniqueColumns(List<String> names) {
        synchronized (LockHolder.LOCK) {
            ... do something
        }
    }
}

ライブラリ全体に関する限り、このトリックは、部外者によって書かれた悪意のあるコードがロックにアクセスするのを防ぐため、 でprivate同期する場合と比較して、ロック オブジェクトを使用する場合と同じ利点があります。thisもちろん、ライブラリのどの部分でもロックを取得できます。

于 2013-12-01T11:48:50.300 に答える
1

インターフェイスに getLock() メソッドを追加して、各実装者にロックするオブジェクトを返すようにさせることができます。

于 2013-12-01T11:38:52.107 に答える
0

それの一体(そしていくつかの娯楽的価値)のために、何が実現可能か見てみましょう...

ロック オブジェクトをパッケージ可視クラスの static フィールドに配置し、すべての既定のメソッドがロックを共有できるようにします。ロック プロバイダーは、インスタンスに独自のロックをオンデマンドで提供します。インスタンスがガベージ コレクションされると、コレクションからロックが削除されます。

ロック プロバイダーは、インスタンスから最初に要求されたときにロックを作成し、その後は同じロックを返します。次のようになります。

final class LockProvider {

    private static final WeakHashMap<Widget,Object> widgetLocks = new WeakHashMap<>();

    static Object obtainLock(Widget w) {
        synchronized (widgetLocks) {            
             return locks.computeIfAbsent(w, x -> new Object());
        }
    }

}

そして、デフォルトのインターフェイス メソッドは次のようになります。

public interface Widget{

    default void addSomething(List<String> names) {
        synchronized (LockProvider.obtainLock(this)) {
            ... do something
        }
    }

}

これの弱点の 1 つは、 と を使用WeakHashMapすることです。もう 1 つは、高速ではありますが、超高性能ではないことです。この方法は巧妙に思えますが、プライベート ロックでの同期を必要とする方法は、別の方法で設計することをお勧めします。Object.hashcode()Object.equals()

[更新しました]

私が最終的にやったことは次のとおりです。

1) デフォルトのメソッドを作成します。

public interface Widget{

    default void addSomething(List<String> something) {
        ... do something 
    }
}

2) 次に、通常の実装とスレッドセーフな実装の両方を作成しました

public class WidgetImpl implements Widget{
    ...
}

// Threadsafe version
public class WidgetThreadsafeImpl implements Widget{

    private final Object lock = new Object(); 

    public void addSomething(List<String> something) {
        synchronized(lock){
            super.addSomething(something);
        }
   }

}

デフォルトのメソッドはアルゴリズムを提供し、実装はスレッドセーフまたは非スレッドセーフの実装を提供できます。

于 2013-12-03T10:29:25.493 に答える