Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.7k views
in Technique[技术] by (71.8m points)

请教一下关于 SynchronizedList以及ConcurrentHashMap锁的问题

想请教一下为什么 SynchronizedList 是读写均加锁,而 ConcurrentHashMap 只有写加了锁,读并没有加锁。
查询了相关资料,ConcurrentHashMap 读不加锁是因为 Node<K,V> 的 val 是用 volatile 声明的,因此保证了他的可见性,这里的 val 是一个对象。
但是我发现 SynchronizedList 中 list 是用 final 声明的, 而没有使用 volatile。
而根据查询到的资料说 volatile 声明对象或者数组,只能让其引用可见,那么他的元素/属性是如何保证可见呢?
自己做了一些简单的测试, 发现 volatile 声明的对象或者数组,他们的属性或者元素都是可见的(也有说是JIT优化产生的结果)如果 volatile 可以实现读的安全的话,SynchronizedList 是否可以使用 volatile 声明 list 而不给读加锁?

public static void main(String[] args) {
    VolatileDemo volatileDemo = new VolatileDemo();
    new Thread(() -> {
      long start = System.currentTimeMillis();
      System.out.println(start);
      for (int i = 0; i < 1000; i++) {
        try {
          volatileDemo.put(i);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      System.out.println("end");
      System.out.println(System.currentTimeMillis() - start);
    }).start();
    
    new Thread(() -> {
      for (; ; ) {
        volatileDemo.printNew();
      }
    }).start();
  }
  
  static class FlagClass{
      boolean hasNew = false;
  }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

ConcurrentHashMap 是采用非阻塞算法实现的,就算是在写的情况下,一般也不会加锁。使用cas速度很快,就是实现相当复杂。SynchronizedList 就可以看成是一个普通的list,给方法都加上了同一个锁来保证安全,这样实现效率非常低。至于volatile 只能保证可见性,不能保证线程安全。就像你说的,如果放在引用上,只能保证引用的可见性。


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...