Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/url/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在接口默认方法内同步而不使用此方法?_Java_Synchronized_Java 8_Default Method - Fatal编程技术网

Java 如何在接口默认方法内同步而不使用此方法?

Java 如何在接口默认方法内同步而不使用此方法?,java,synchronized,java-8,default-method,Java,Synchronized,Java 8,Default Method,我在需要同步的接口中有许多默认方法,似乎只有这个可用: default void addUniqueColumns(List<String> names) { synchronized (this) { ... do something } } 解决方案?聪明的变通办法?或者只是接受它:) 您可以将getLock()方法添加到接口中,并让每个实现者返回要锁定的对象。您可以将lock对象放入包可见类的公共静态字段中,让所有默认方法共享锁。锁在库内仍然可

我在需要同步的接口中有许多默认方法,似乎只有
这个
可用:

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

解决方案?聪明的变通办法?或者只是接受它:)

您可以将getLock()方法添加到接口中,并让每个实现者返回要锁定的对象。

您可以将lock对象放入包可见类的公共静态字段中,让所有默认方法共享锁。锁在库内仍然可见,但由于具有默认访问权限的类在库外不可见,因此锁对于库外接口的用户是私有的:

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
        }
    }
}
类锁持有者{//包私有类
公共静态对象锁=新对象();
}
公共接口列集合{
默认的void addUniqueColumns(列表名称){
同步(锁夹.锁){
…做点什么
}
}
}
就整个库而言,与在
this
上同步相比,使用
private
锁对象具有与在
this
上同步相同的优势,因为它可以防止外部用户编写的恶意代码访问您的锁。当然,锁可以被你的库的任何部分抓住。

关于它(以及一些娱乐价值),让我们看看什么是可行的。。。 我将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
        }
    }

}
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);
        }
   }

}
公共类WidgetImpl实现小部件{
...
}
//线程安全版本
公共类WidgetThreadsafeImpl实现小部件{
私有最终对象锁=新对象();
公共空添加某物(列出某物){
已同步(锁定){
超级。添加某物(某物);
}
}
}

默认方法提供算法,实现可以提供线程安全或非线程安全的实现。

Object lock=new Object()@marounnaroun我发布了这个答案,但这是关于接口默认方法的。我得再检查一下。@SaintHill你能添加一个
对象lockObject()吗方法到默认方法可以引用的接口?hmmm。。。别这么想。无法将私有方法添加到接口…您将滥用语言功能。一个接口意味着不管它是否有默认方法,它都是一个接口。您将要编写的是一个抽象类。因此,只需为其使用抽象类,而不是滥用带有默认方法功能的接口。这并不是OP想要的私有锁对象,尽管这在很大程度上违背了目的。公平地说,尽管我认为在接口中不可能做到这一点。当然,实现者内部的锁可以是私有的,这是一种有趣的方法。尽管如此,我不确定我是否想要一个可以在包中共享的锁。我知道这可能是不可能的,方法必须被移动到抽象类中。@SaintHill Java中没有绝对的保护,至少只要它有反射就没有。选择权归你——抽象类给你的灵活性要小得多,但是锁可能是类的私有锁。另一方面,使用抽象类可以避免包私有静态成员。有趣的是,几小时前我问自己,为什么有人会尝试使用默认方法而不是普通的旧抽象类来实现这一点。有什么好处?@mwhs这是个很好的问题,同样的推理也适用于Java的默认方法。@dasblinkenlight那么默认方法基本上告诉开发人员停止滥用/扭曲继承以避免冗余?那很酷。前几天,我在想,在OOD中有多少模式实际上是为了避免冗余或强制执行DRY。“你应该修正你的设计,使用抽象类而不是接口,而不是发明这样的乱七八糟的东西。”我听到了回音吗??读序言!至于这个问题。。我把它修好了是的,你听到回声了。有些事情太重要了,不能只说一次顺便说一句,如果要解决这个问题,最好的解决方案是使用并发映射(它提供一个原子的
computeIfAbsent
)和一个从
WeakReference
派生的自定义密钥类,包装小部件并将小部件的
System.identityHashCode
用作它自己的
hashCode>。这将一次解决所有的缺陷。@Holger聪明的想法!请随意编辑答案与您的修复在这里。如果有机会,我会的。
public interface Widget{

    default void addSomething(List<String> something) {
        ... do something 
    }
}
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);
        }
   }

}