我刚刚考虑了如何在从不同线程修改变量(如int)时锁定它。我不习惯这样使用它,我知道Java中的synchronized关键字,但我想了解它以及它的一般工作原理。
这就是我的代码:
private int i = 0;
private int lock = 0;
public void count(int lock) {
while (true) {
if (this.lock == 0) {
this.lock = lock;
}
if (this.lock == lock) {
i ++;
this.lock = 0;
return;
}
}
}
问题是:它有效吗?这个反螺纹安全吗?如果是:同步关键字是simmilar作业吗?如果没有:为什么不呢?
Edit:我忘了提到每个线程都用不同的锁值调用count方法。
简单的答案是"不",不能保证线程安全。
较长的答案是,您需要查看Java内存模型来了解原因。部分问题是不同的线程可能无法同时看到更改。内存模型只保证写入后的读取在执行写入的同一线程中看到更新的值,除非越过内存屏障。另一个线程可能看不到更新,即使它在其他线程执行写入之后执行读取。除非使用volatile
关键字描述变量。或者使用synchronized
关键字来确保只有一个线程在更新该值。这种行为允许Java运行时优化代码,也许是通过在循环中内联它注意到的常量,还可以使用本机汇编语言,不能提供同步性保证,但速度明显更快。
问题的另一部分是,当两个更新同时发生在不同的线程上时,确保两个线程都能获得相同结果的唯一方法是使用相应的低级汇编语言指令,这些指令可能被称为compareAndSet、compareAndSwap或testAndSet。
因此,对于您编写的代码来说,这种执行顺序的等效性是完全可能的(其中T1和T2是单独的线程)。。。
// assuming i begins at 0.
T1: if this.lock == true
T2: if this.lock == true
T1: this.lock = lock
T1: if this.lock == lock // evaluates to true
T2: if this.lock == lock // evaluates to true
T1: this.lock = lock
T2: this.lock = lock
它实际上更复杂,因为你不能说每个指令都是CPU上的一条指令。从根本上讲,可以让两个线程同时执行某种更新,所有随之而来的结果都是重复或丢失更新。
更简单的答案是:将java.util.concurrent
中提供的Atomic原语用于线程安全计数器。