有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

同步表达式内的java方法引用

对不起,伙计们,但我不明白,在哪个对象上是synchronized块内sync()方法是同步的:

public class TestLambda {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    sync();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    static void sync() throws InterruptedException {
        synchronized ((Runnable)TestLambda::new) {
            System.out.println("inside");
            Thread.sleep(1000L);
        }
    }
}

如果在方法引用对象上,为什么我不能只写: synchronized (TestLambda::new)?(这将是编译时错误)

有什么想法吗

UPD:以防万一:它确实是同步的

UPD-2:对于那些怀疑的人,举个简单的例子:

C:\sandbox\research\learn8\src>"C:\Program Files\Java\jdk1.8.0_31\bin\"javac TestLambda.java
TestLambda.java:27: error: method reference not expected here
    public class Test { { synchronized (Test::new) { System.out.println("sync"); } } }
                                        ^
1 error

共 (2) 个答案

  1. # 1 楼答案

    让我们看看下面两个作业:

    Supplier<TestLambda> supp = TestLambda::new;
    Runnable runnable = TestLambda::new;
    

    这两本书都很好。基本上是因为lambda或方法引用可以兼容多个功能接口。这意味着,仅仅写TestLambda::new并不能告诉我们所创建对象的确切运行时类型。实例化哪个接口取决于目标类型。目标类型应该始终是一个功能接口,而不是下面的语句中的情况:

    synchronized(TestLambda::new) {
    }
    

    因此,编译器不允许这样做,因为运行时无法决定实例化哪个函数接口。您可以通过将方法引用转换为Runnable来提供该信息。因此,在下面的声明中:

    synchronized((Runnable) TestLambda::new) {
    }
    

    运行时将实例化实现Runnable接口的类对象。从某种意义上说,铸件为方法参考提供了具体性

    为了给出一个模糊的概念,可以这样翻译:

    class RuntimeClass implements Runnable {
        public void run() {
            TestLambda testLambda = new TestLambda();
        }
    }
    
    synchronized(new RuntimeClass()) {
    }
    

    p.S:的实际实例RuntimeClass将是singleton(因为我们使用的是无状态方法表达式)我最初的错误语句

    p.p.S:从@Stuart的评论中可以看出,对于lambda或方法引用,不保证会创建新实例还是返回新实例。所以,你不应该在它们上同步

  2. # 2 楼答案

    JLS 14.19. The synchronized Statement

    SynchronizedStatement:
        synchronized ( Expression ) Block
    

    The type of Expression must be a reference type, or a compile-time error occurs.


    JLS 15.13.2. Type of a Method Reference

    A method reference expression is compatible in an assignment context, invocation context, or casting context with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of the ground target type derived from T.

    上述两个规定应该勾勒出一幅画面:synchronized语句采用任何引用类型的表达式,方法引用与作为函数接口的任何目标引用类型T兼容。注意Object不满足这一点

    换句话说,还有一个自由度:方法引用应该与哪种引用类型兼容?这种自由必须被显式类型转换剥夺,强制转换为特定类型。只有到那时,整个表达式的类型才为人所知