zoukankan      html  css  js  c++  java
  • java多线程 -- ConcurrentHashMap 锁分段 机制

    hashtable效率低
    ConcurrentHashMap 线程安全,效率高

    Java 5.0 在 java.util.concurrent 包中提供了多种并发容器类来改进同步容器 的性能。

    1. ConcurrentHashMap 同步容器类是Java 5 增加的一个线程安全的哈希表。对 与多线程的操作,介于 HashMap 与 Hashtable 之间。内部采用“锁分段”机制替代 Hashtable 的独占锁。进而提高性能。
    2. 此包还提供了设计用于多线程上下文中的 Collection 实现:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和 CopyOnWriteArraySet。当期望许多线程访问一个给 定 collection 时,ConcurrentHashMap 通常优于同步的 HashMap,ConcurrentSkipListMap 通常优于同步的 TreeMap。当期望的读数和遍历远远 大于列表的更新数时,CopyOnWriteArrayList 优于同步的 ArrayList。

    关于锁分段机制:

    HashTable容器在竞争激烈的并发环境下表现出效率低下的原因是所有访问HashTable的线程都必须竞争同一把锁,假如容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效提高并发访问效率,这就是ConcurrentHashMap所使用的锁分段技术。首先将数据分成一段一段地存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问

    Segment是一种可重入锁(ReentrantLock),在ConcurrentHashMap里扮演锁的角色;
    HashEntry则用于存储键值对数据;

    --引自 《java并发编程的艺术》

    ConcurrentHashMap 和HashMap方法基本上保持一致。

    当多线程访问并处理List的时候会出现并发修改异常:

    Exception in thread "Thread-8" java.util.ConcurrentModificationException
        at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
        at java.util.ArrayList$Itr.next(ArrayList.java:851)
        at com.company.HelloThread.run(TestCopyOnWriteArrayList.java:42)
        at java.lang.Thread.run(Thread.java:745)
    Exception in thread "Thread-7" Exception in thread "Thread-9" java.util.ConcurrentModificationException
        at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
        at java.util.ArrayList$Itr.next(ArrayList.java:851)
        at com.company.HelloThread.run(TestCopyOnWriteArrayList.java:42)
        at java.lang.Thread.run(Thread.java:745)

    出现这种情况demo:

    package com.company;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.List;
    
    public class TestCopyOnWriteArrayList {
    
        public static void main(String[] args) {
            HelloThread ht = new HelloThread();
    
            for (int i = 0; i < 10; i++) {
                new Thread(ht).start();
            }
        }
    
    }
    
    class HelloThread implements Runnable {
    
        private static List<String> list = Collections.synchronizedList(new ArrayList<String>());
    
        static {
            list.add("小王");
            list.add("中王");
            list.add("大王");
        }
    
        @Override
        public void run() {
    
            Iterator<String> it = list.iterator();
    
            while (it.hasNext()) {
                System.out.println(it.next());
    
                list.add("==");
            }
    
        }
    
    }

    那么如果避免多线程下这种问题的产生呢,利用CopyOnWriteArrayList :

    import java.util.Iterator;
    import java.util.concurrent.CopyOnWriteArrayList;
    
    /*
     * CopyOnWriteArrayList/CopyOnWriteArraySet : “写入并复制”
     * 注意:添加操作多时,效率低,因为每次添加时都会进行复制,开销非常的大。并发迭代操作多时可以选择。
     */
    public class TestCopyOnWriteArrayList {
    
        public static void main(String[] args) {
            HelloThread ht = new HelloThread();
    
            for (int i = 0; i < 10; i++) {
                new Thread(ht).start();
            }
        }
    
    }
    
    class HelloThread implements Runnable {
    
    //    private static List<String> list = Collections.synchronizedList(new ArrayList<String>());
    
        private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
    
        static {
            list.add("大王A");
            list.add("大王B");
            list.add("大王C");
        }
    
        @Override
        public void run() {
    
            Iterator<String> it = list.iterator();
    
            while (it.hasNext()) {
                System.out.println(it.next());
    
                list.add("====");
            }
    
        }
    
    }

    结果:

    大王A
    大王A
    大王A
    大王B
    大王A
    大王B
    大王A
    大王B
    大王C
    大王A
    大王A
    大王B
    大王C
    ====
    大王C
    大王B
    大王B
    大王C
    ====
    大王A
    大王C
    ====
    大王A
    ====
    ====
    大王B
    大王C
    ====
    大王B
    大王A
    ====
    大王C
    ====
    ====
    ====
    大王B
    大王C
    ====
    ====
    大王B
    ====
    ====
    ====
    ====
    大王C
    ====
    ====
    ====
    ====
    ====
    大王C
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
    ====
  • 相关阅读:
    面向对象的继承关系体现在数据结构上时,如何表示
    codeforces 584C Marina and Vasya
    codeforces 602A Two Bases
    LA 4329 PingPong
    codeforces 584B Kolya and Tanya
    codeforces 584A Olesya and Rodion
    codeforces 583B Robot's Task
    codeforces 583A Asphalting Roads
    codeforces 581C Developing Skills
    codeforces 581A Vasya the Hipster
  • 原文地址:https://www.cnblogs.com/androidsuperman/p/6637073.html
Copyright © 2011-2022 走看看