多线程:锁定并设置



我知道,在与多个线程一起使用的程序中,有必要同步方法,因为可能会有诸如种族条件之类的问题。
但是我不明白为什么我们还需要同步仅读取共享变量的方法。
查看此示例:

public ConcurrentIntegerArray(final int size) { 
    arr = new int[size]; 
} 
public void set(final int index, final int value) { 
    lock.lock(); 
    try { 
        arr[index] = value; 
    } finally { 
        lock.unlock(); 
    } 
} 
public int get(final int index) { 
    lock.lock(); 
    try { 
        return arr[index]; 
    } finally { 
        lock.unlock(); 
    } 
} 


他们对GET和设定方法进行了查看。
在设定方法上,我了解原因。例如,如果我想将thread1放在索引= 3中,数字5,在一毫秒之后,thread2必须放入index = 3数字6。

是否会发生我在index = 3 in我的数组仍然是5而不是6(如果我不在方法集上进行同步)?

这是因为thread1可以具有switch-context,因此thread2在同一方法中输入值和线程1在同一位置分配值5之后,所以而不是6我有5个。


但是我不明白为什么我们需要(示例)也可以同步方法。
我问这个问题,因为我们只需要在记忆上阅读而不是写入。




那么,为什么我们还需要该方法具有同步呢?有人可以给我一个非常简单的例子吗?

两种方法都需要同步。在get方法上没有同步,此序列是可能的:

  1. get被称为,但旧值尚未返回。
  2. 另一个线程调用set并更新值。
  3. 现在称为get的第一个线程现在检查了现在返回的值并看到现在过时的值。

同步将通过保证另一个线程不能只调用set并在返回get值无效的情况下禁止这种情况。它将迫使一个呼叫set的线程等待调用get完成的线程。

如果您不锁定GET方法,则可能会保留数组的本地副本,而绝不会从主内存中刷新。因此,get永远不会看到通过设置方法更新的值。锁会迫使可见度。

每个线程保持自己的价值副本。同步确保在不同线之间保持相干性。没有同步,就永远无法确定是否有人对其进行了修改。另外,可以将变量定义为挥发性,并且它将具有与同步相同的内存效应。

锁定操作还保证了内存可见性。从锁文档:

所有 lock 实现必须强制执行相同的内存同步语义,该语义与内置的监视器锁定相同,[...]:

  • 成功的操作具有与成功的锁定动作相同的内存同步效果。

  • 成功的 Unlock 操作具有与成功的 Unlock Action相同的内存同步效果。

由于内存一致性错误而没有获得锁定,因此没有理由对get进行调用,需要查看最新的值。现代处理器非常快,访问DRAM的速度相对较慢,因此处理器存储了他们在本地缓存中工作的值。在并发编程中,这意味着一个线程可能会在内存中写入变量,但是随后从其他线程读取的读取值是一个过时的值,因为它是从缓存中读取的。

锁定保证该值实际上是从内存而不是从缓存中读取的。

最新更新