それの一体(そしていくつかの娯楽的価値)のために、何が実現可能か見てみましょう...
ロック オブジェクトをパッケージ可視クラスの 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);
}
}
}
デフォルトのメソッドはアルゴリズムを提供し、実装はスレッドセーフまたは非スレッドセーフの実装を提供できます。