Java 8方法引用不启动线程?

时间:2017-07-04 20:22:10

标签: java java-8

为什么方法引用不会在此示例中启动线程?

package example;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ESMethodReference {
    int i1, i2, result = 0;

    ESMethodReference(int i1, int i2){
        this.i1 =i1;
        this.i2 = i2;
    }

    public Runnable calculate(){
        System.out.print("In calculate()");
        return new Runnable() {
            @Override
            public void run() {
                result += i1 + i2;          
                System.out.print(" creating result");
            }
        };
    }

    public static void main(String[] args) throws InterruptedException{
        ESMethodReference es = new ESMethodReference(1, 1);

        ExecutorService executorService = Executors.newSingleThreadExecutor();

        for (int i = 0; i < 2; i++){
            executorService.submit(es.calculate());
            Thread.sleep(100);  // Allow new thread to run      
            System.out.println("\tes.calculate() result incremented " + es.result );

            executorService.submit(es::calculate);
            Thread.sleep(100);  // Allow new thread to run      
            System.out.println("\tes::calculate result NOT incremented " + es.result );
        }

        executorService.shutdown();
    }
}

输出:
在calculate()中创建结果es.calculate()结果递增2
在calculate()es :: calculate结果中,NOT递增2
在calculate()中创建结果es.calculate()结果递增4
在calculate()es :: calculate结果中,NOT递增4

3 个答案:

答案 0 :(得分:11)

因为那些是不同的东西 - 传递es::calculate与传递相同:

new Runnable() {
     @Override
     public void run() {
         es.calculate();
     }
}

显然,这与:

不一样
new Runnable() {
     @Override
     public void run() {
         es.calculate().run();
     }
}

答案 1 :(得分:5)

当您致电es.calculate()时,会返回带有代码

Runnable
public void run() {
    result += i1 + i2;          
    System.out.print(" creating result");
}

当您传递方法引用es::calculate时,代码运行将是

System.out.print("In calculate()");
return new Runnable() {
    @Override
    public void run() {
        result += i1 + i2;          
        System.out.print(" creating result");
    }
};

执行方法的返回值和通过方法引用执行方法本身之间存在差异。

答案 2 :(得分:3)

executorService.submit(es::calculate);

相当于

executorService.submit(() -> es.calculate());

不一样
executorService.submit(es.calculate());

前者异步创建Runnable(不执行它),而后者异步执行相同Runnable的(不同实例)。

作为旁注,如果只创建任务而不计算任何内容,则应该避免命名方法“ calculate ”。例如,如果将其命名为createTask(),则会更明显地表明以下内容不会计算任何内容:

executorService.submit(es::createTask)

或者,如果您使方法实际计算结果:

public void calculate(){
    System.out.print("In calculate()");
    result += i1 + i2;
    System.out.print(" creating result");
}

然后使用方法引用的调用将按预期工作。