从Lambda调用的方法无法访问字段?
我一直在尝试lambdas,遇到了一个我不理解的问题。下面的代码可以独立工作,但在多线程环境(我无法控制)中运行它会导致从Lambda调用的方法无法访问字段?,lambda,java-8,Lambda,Java 8,我一直在尝试lambdas,遇到了一个我不理解的问题。下面的代码可以独立工作,但在多线程环境(我无法控制)中运行它会导致run()位于一个实例中,而doA()位于另一个实例中,我可以在调试器中将其视为不同的实例ID public class Main { private String string; public static void main(String[] args) { Main main = new Main(); Main main
run()
位于一个实例中,而doA()
位于另一个实例中,我可以在调试器中将其视为不同的实例ID
public class Main {
private String string;
public static void main(String[] args) {
Main main = new Main();
Main main2 = new Main();
main2.run();
}
private interface Stepper {
boolean execute();
}
Stepper[] steps = { () -> { return doA(); }, () -> { return doB(); }, () -> { return doC(); } };
public boolean doA() { System.out.println(string); return true; }
public boolean doB() { System.out.println(string); string = "foo"; return true; }
public boolean doC() { System.out.println(string); return true; }
private void run() {
string = "changed";
for (Stepper step : steps) {
if (step.execute() == false) {
return;
}
}
}
}
real类实现了
Runnable
的专有子体,此处未显示该子体。我将步骤的初始化
移动到run()
方法中,它开始正常工作。让数组位于run()
方法之外怎么会导致这种情况?如果更改步进器接口,可以执行以下操作:
public class Main {
private String string;
public static void main(String[] args) {
Main main = new Main();
Main main2 = new Main();
main2.run();
}
private interface Stepper extends Function<Main, Boolean> {
default boolean execute(Main main){
return this.apply(main);
}
}
Stepper[] steps = {Main::doA, Main::doB, Main::doC};
public boolean doA() { System.out.println(string); return true; }
public boolean doB() { System.out.println(string); string = "foo"; return true; }
public boolean doC() { System.out.println(string); return true; }
private void run() {
string = "changed";
for (Stepper step : steps) {
if (step.execute(this) == false) {
return;
}
}
}
}
公共类主{
私有字符串;
公共静态void main(字符串[]args){
Main Main=新Main();
Main Main 2=新的Main();
main2.run();
}
专用接口步进器扩展功能{
默认布尔值执行(主){
返回此。应用(主);
}
}
步进器[]步骤={Main::doA,Main::doB,Main::doC};
公共布尔doA(){System.out.println(字符串);返回true;}
公共布尔值doB(){System.out.println(string);string=“foo”返回true;}
public boolean doC(){System.out.println(字符串);返回true;}
私家车{
string=“已更改”;
用于(步进器步进:步进){
如果(步骤执行(此)=错误){
返回;
}
}
}
}
这是因为方法引用是静态的,但将This
传递给execute函数可确保当前实例始终是将要操作的实例
如果您有一个多线程环境,那么没有什么可以阻止另一个线程同时运行并与这个实例的输出交叉。我建议您将输出收集到一个StringBuilder
中,并将其作为一个操作打印出来,以确保输出不会交错。如果顺序不重要,那么就足够公平了,但这肯定会使调试更容易知道每组输出来自同一个线程。您甚至可以考虑将线程ID添加到输出行。您将需要发布一个可重复的示例。多线程如何?什么是并发调用的?您有多少个Main
实例?那句话没有意义。这是什么意思?您是说在与doA
不同的实例上调用run()
?这意味着要实例化的类有多个实例。我们必须了解实例是如何使用的。正如这里所写的,这是不可能的。您可以将steps
的声明更改为private final
,但无论如何,如果您声称不应该有多个实例,您应该开始查看调用构造函数的人(不止一次)以找出实例的来源。尽管如此,正如本文所述,lambda表达式的实例与特定实例耦合。