我尝试更改并使用 lambda 获取局部变量。我知道我应该对 lambda 中的局部变量使用有效的final。当我使用 AtomicReference 局部变量更改失败时:
public class Lamb {
public static void main(String[] args) throws InterruptedException {
Lamb lamb = new Lamb();
GlobalL globalL = new GlobalL();
lamb.a(globalL);
for (int i = 0; i < 100; i++) {
new Thread(() -> {
globalL.printSum();
}).start();
}
Thread.sleep(3000);
System.out.println("--------After Work--------");
globalL.printSum();
}
public void a(GlobalL globalL) {
AtomicReference<Integer> number = new AtomicReference<>(0);
Work work = () -> {
number.getAndSet(number.get() + 1);
return number.get();
};
globalL.setWork(work);
}
}
class GlobalL {
private Work work;
public void printSum() {
System.out.println(work.getAndInc());
}
public void setWork(Work work) {
this.work = work;
}
}
interface Work {
int getAndInc();
}
每次输出不同:
- --------下类后--------
97 - --------下类后--------
99
当我将 Atomic 更改为数组时,此工作正常:
public void a(GlobalL globalL) {
Integer[] number = {1};
Work work = () -> {
number[0]++;
return number[0];
};
globalL.setWork(work);
}
每次输出:
--------下类后--------
102
- 数组和原子这种情况是怎么回事?
- 如何使用非最终局部变量使用匿名类和 labmda?
- jvm 如何与 lamda 配合使用?
最佳答案
1)代码:
number.getAndSet(number.get() + 1);
return number.get();
是一个关键部分,因为有几个操作不是原子执行的。这就是为什么你会得到不同的结果。消除关键部分:
public void a(GlobalL globalL) {
AtomicInteger number = new AtomicInteger(0);
Work work = () -> {
return number.incrementAndGet();
};
globalL.setWork(work);
}
2) 你不能(参见this或the official tutorial on Anonymous Classes)
3)IMO,这应该是一个单独的问题。简而言之,lambda 只是语法糖,它们被编译成匿名内部类。
<小时/>至于为什么数组可以正常工作?
问题,答案是:不能,原因相同:++ is not an atomic operator
为了证明这一点,只需将线程数增加到 1000:
for (int i = 0; i < 1000; i++) {
new Thread(() -> {
globalL.printSum();
}).start();
}
我得到:
--------After Work-------- 972
关于java - 本地 AtomicReference 和带有 lambda 的数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60408193/