具有 lambda 的本地 AtomicReference 和数组
Local AtomicReference and array with lambda
我尝试使用 lambda 更改并获取局部变量。我知道我应该对 lambda 中的局部变量使用 effectively 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
- array和atomic这种情况是怎么回事?
- 如何使用非 final 局部变量的匿名 class 和 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) 你不能(参见 or the official tutorial on Anonymous Classes)
3) IMO,这应该是一个单独的问题。简而言之,lambdas 只是语法糖,它们被编译成匿名内部 类.
至于why array works correctly?
问题,答案是:不会 同理:++ is not an atomic operator
为了证明这一点,只需将线程数增加到 1000:
for (int i = 0; i < 1000; i++) {
new Thread(() -> {
globalL.printSum();
}).start();
}
我得到:
--------After Work-------- 972
我尝试使用 lambda 更改并获取局部变量。我知道我应该对 lambda 中的局部变量使用 effectively 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
- array和atomic这种情况是怎么回事?
- 如何使用非 final 局部变量的匿名 class 和 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) 你不能(参见
3) IMO,这应该是一个单独的问题。简而言之,lambdas 只是语法糖,它们被编译成匿名内部 类.
至于why array works correctly?
问题,答案是:不会 同理:++ is not an atomic operator
为了证明这一点,只需将线程数增加到 1000:
for (int i = 0; i < 1000; i++) {
new Thread(() -> {
globalL.printSum();
}).start();
}
我得到:
--------After Work-------- 972