我在需要同步的接口中有许多默认方法,似乎只有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
}
}
解决方案?聪明的解决方法?或者只是和它一起生活:)!
答案 0 :(得分:2)
您可以将锁定对象放入包可见类的公共静态字段中,让所有默认方法共享锁定。锁在您的库中仍然可见,但由于具有默认访问权限的类在您的库外部不可见,因此该锁对于您的库外库的接口用户是私有的:
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
上的同步相比具有相同的优势,因为它可以防止外人写的恶意代码从访问你的锁。当然锁可以被你图书馆的任何部分抓住。
答案 1 :(得分:1)
您可以在接口中添加一个getLock()方法,并让每个实现者返回要锁定的对象。
答案 2 :(得分:0)
我将lock对象放入包可见类的静态字段中,让所有默认方法共享锁。锁提供程序按需提供实例自己的锁。当实例被垃圾收集时,锁将从集合中删除。
锁提供程序在第一次从实例请求时创建锁,然后再返回相同的锁。它看起来像这样:
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
}
}
}
这样做的一个缺点是WeakHashMap
使用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);
}
}
}
默认方法提供了一种算法,实现可以提供线程安全或非线程安全的实现。