Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/402.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 多线程:锁定get和set_Java_Multithreading_Locking - Fatal编程技术网

Java 多线程:锁定get和set

Java 多线程:锁定get和set,java,multithreading,locking,Java,Multithreading,Locking,我知道,在一个使用多线程的程序中,有必要同步这些方法,因为可能会出现诸如争用条件之类的问题。 但是我不明白为什么我们还需要同步那些只需要读取共享变量的方法 看看这个例子: public ConcurrentIntegerArray(final int size) { arr = new int[size]; } public void set(final int index, final int value) { lock.lock(); try {

我知道,在一个使用多线程的程序中,有必要同步这些方法,因为可能会出现诸如争用条件之类的问题。
但是我不明白为什么我们还需要同步那些只需要读取共享变量的方法
看看这个例子:

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和set方法。
关于set方法,我理解原因。例如,如果我想将Thread1放在index=3中,则数毫秒后Thread2必须将index=3放在数6中

数组中的index=3是否仍然是5而不是6(如果我没有对方法集进行同步)?

这是因为Thread1可以有一个切换上下文,因此Thread2以相同的方法输入值,并在Thread1之后将值5分配到相同的位置,因此我有一个5,而不是6。


但是我不明白为什么我们还需要(查看示例)同步方法get。
我问这个问题是因为我们只需要在内存上读取,而不需要写入。

那么为什么我们还需要在方法get上进行同步呢?有人能给我举个简单的例子吗

如果不锁定get方法,线程可能会保留数组的本地副本,并且永远不会从主存刷新。因此,get可能从未看到由set方法更新的值。锁定将强制保持可见性

每个线程都维护自己的值副本。synchronized确保不同线程之间保持一致性。如果没有同步,就永远无法确定是否有人对其进行了修改。或者,可以将变量定义为volatile,它将具有与synchronized相同的内存效果。

这两种方法都需要同步。如果不使用
get
方法进行同步,则可以执行以下顺序:

  • 调用了
    get
    ,但尚未返回旧值
  • 另一个线程调用
    set
    并更新该值
  • 第一个调用
    get
    的线程现在检查现在返回的值,并查看什么是过时的值

  • 通过保证另一个线程不能在
    get
    值返回之前调用
    set
    并使其无效,同步将禁止这种情况。它将强制调用
    set
    的线程等待调用
    get
    的线程完成。

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

    所有实现必须强制执行与内置监视器锁[…]提供的相同的内存同步语义:

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

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

    在不获取锁的情况下,由于,调用
    get
    无需查看最新值。现代处理器速度非常快,对DRAM的访问速度相对较慢,因此处理器将处理的值存储在本地缓存中。在并发编程中,这意味着一个线程可能会写入内存中的变量,但随后从另一个线程读取的变量会得到一个过时的值,因为它是从缓存读取的


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

    你说的“可见性”是什么意思?你似乎在说锁定可以防止一种交织,在这种情况下,set调用可以在where get读取值和返回值之间完成。这似乎不是一个很好的理由,因为从技术上讲,锁仍然可能发生这种情况。@Radiodef锁将防止
    set
    方法在
    get
    方法检索值时更改该值。一旦
    get
    返回了值并放弃了锁,那么
    set
    当然可以更改值。如果我理解你的意思,如果我不将锁也放在set方法上,我可能会“丢失”一些信息?示例:在索引3中的数组中,我有一个5,我调用get方法来获取这个值(5),但在读取这个值之前还有另一个线程。。。在集合方法中输入,并在索引3上输入10。。。所以在使用get方法后,我得到的是10而不是5。。。我的解释是正确的?如果
    get
    中没有锁定,您可以返回过期信息。如果索引3有一个
    5
    ,则调用get方法,检索该值,但它没有机会返回该值。调用
    set
    ,并将该索引处的值设置为
    10
    。然后,
    get
    方法返回一个过时的值,
    5
    。另请参见