同步表达式内的方法引用

时间:2015-04-03 20:21:14

标签: java java-8 method-reference

对不起大家,但我无法理解,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 个答案:

答案 0 :(得分:3)

让我们看看以下2个作业:

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的实际实例将是单例(因为我们正在使用无状态方法表达式) - 我原来的错误陈述

P.P.S :正如@Stuart的评论所指出的那样,无法保证对于lambda或方法引用,是否会创建新实例或返回相同的实例。所以,你不应该同步它们。

答案 1 :(得分:3)

  

JLS 14.19。 synchronized声明

SynchronizedStatement:
    synchronized ( Expression ) Block
     

Expression 的类型必须是引用类型,否则会发生编译时错误。


  

JLS 15.13.2。方法参考的类型

     

如果T是函数接口类型(第9.8节)且表达式与地面目标类型的函数类型一致,则方法引用表达式在赋值上下文,调用上下文或具有目标类型T的转换上下文中是兼容的源自T。

以上两个规定应该描绘:synchronized语句采用任何引用类型表达式,方法引用兼容任何目标引用类型T是一个功能接口。请注意Object不满足此要求。

换句话说,还有一定的自由度:方法参考应该与哪个完全相同的参考类型?这种自由必须通过显式类型转换来消除,这会强制它进入特定类型。只有这样才能知道整个表达的类型。