如果2个不同的写入和读取线程永远不会同时存在,我是否需要使用volatile

Che*_*eng 5 java multithreading

通过参考http://www.javamex.com/tutorials/synchronization_volatile.shtml,由于附加规则3,我不确定volatile在下列情况下是否需要使用关键字.

  1. 原始静态变量将由线程A写入.
  2. 线程B将读取相同的原始静态变量.
  3. 线程B只会在线程A"死"后运行.("死"表示,线程A的无效运行的最后一个语句已完成)

线程A写入的新值是否会在"死"之后始终提交给主内存?如果是,是否意味着volatile如果符合上述3个条件我不需要关键字?

我怀疑volatile在这种情况下是否需要.根据需要,ArrayList可能会损坏.由于一个线程可以执行插入和更新size成员变量.后来,另一个线程(不同时地)可以读取ArrayListsize.如果查看ArrayList源代码,size则不会被声明为volatile.

在JavaDoc中ArrayList,只提到ArrayList用于多个线程同时访问ArrayList实例是不安全的,但是不能让多个线程在不同的时间访问ArrayList实例.

让我使用以下代码来解决此问题

public static void main(String[] args) throws InterruptedException {
    // Create and start the thread
    final ArrayList<String> list = new ArrayList<String>();
    Thread writeThread = new Thread(new Runnable() {
        public void run() {
            list.add("hello");
        }
    });
    writeThread.join();
    Thread readThread = new Thread(new Runnable() {
        public void run() {
            // Does it guarantee that list.size will always return 1, as this list
            // is manipulated by different thread?
            // Take note that, within implementation of ArrayList, member
            // variable size is not marked as volatile.
            assert(1 == list.size());
        }
    });
    readThread.join();
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 6

是的,您仍然需要使用volatile(或其他形式的同步).

原因是两个线程可以在不同的处理器上运行,即使一个线程在另一个线程开始之前已经完成了很长时间,也不能保证第二个线程在进行读取时会获得最新的值.如果该字段未标记为volatile并且未使用其他同步,则第二个线程可以获取在其运行的处理器上本地缓存的值.理论上缓存的值可能在很长一段时间内都是过时的,包括在第一个线程完成之后.

如果使用volatile,则将始终将值写入主内存并从主内存中读取,从而绕过处理器的缓存值.