To understand that it might be possible ...
I put the lock object in the static field of the visible package class, allowing all my methods to share the lock by default. The lock provider provides instances of its own locks on demand. The lock is removed from the collection when the instance collects garbage.
The lock provider creates the lock on the first request from the instance and then returns the same lock. It looks like this:
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()); } } }
And now the default interface method is as follows:
public interface Widget{ default void addSomething(List<String> names) { synchronized (LockProvider.obtainLock(this)) { ... do something } } }
One weakness is that WeakHashMap uses Object.hashcode() and Object.equals() . Another thing is that, although fast, it is not super-high-performance. Although this doiung method seems smart ... any method that requires synchronization on a closed lock will be better developed in a different way.
[UPDATED]
In the end, I did the following:
1) create default methods:
public interface Widget{ default void addSomething(List<String> something) { ... do something } }
2) Then both regular and thread safe implementations were created
public class WidgetImpl implements Widget{ ... }
The default method provides an algorithm, and implementations can provide thread-safe or non-thread-safe implementations.
source share