美文网首页JUC编程-线程高级应用
JUC线程高级---ConcurrentHashMap和闭锁

JUC线程高级---ConcurrentHashMap和闭锁

作者: ZebraWei | 来源:发表于2018-05-30 17:53 被阅读17次

**版权声明:本文为小斑马伟原创文章,转载请注明出处!
ConcurrentHashMap:同步容器类是Java 5 增加的一个线程安全的哈希表。对与多线程的操作,介于HashMap 与Hashtable 之间。内部采用“锁分段”机制替代Hashtable 的独占锁。进而提高性能。
ConcurrentHashMap具体是怎么实现线程安全的呢,肯定不可能是每个方法加synchronized,那样就变成了HashTable。

它引入了一个“分段锁”的概念,具体可以理解为把一个大的Map拆分成N个小的HashTable,根据key.hashCode()来决定把key放到哪个HashTable中。

在ConcurrentHashMap中,就是把Map分成了N个Segment,put和get的时候,都是现根据key.hashCode()算出放到哪个Segment中。


测试程序:
import java.util.concurrent.ConcurrentHashMap;  

public class ConcurrentHashMapTest {  
  
private static ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<Integer, Integer>();  
public static void main(String[] args) {  
    new Thread("Thread1"){  
        @Override  
        public void run() {  
            map.put(3, 33);  
        }  
    };  
      
    new Thread("Thread2"){  
        @Override  
        public void run() {  
            map.put(4, 44);  
        }  
    };  
      
    new Thread("Thread3"){  
        @Override  
        public void run() {  
            map.put(7, 77);  
        }  
    };  
    System.out.println(map);  
}  

ConcurrentHashMap中默认是把segments初始化为长度为16的数组。
根据ConcurrentHashMap.segmentFor的算法,3、4对应的Segment都是segments[1],7对应的Segment是segments[12]。

(1)Thread1和Thread2先后进入Segment.put方法时,Thread1会首先获取到锁,可以进入,而Thread2则会阻塞在锁上:



(2)切换到Thread3,也走到Segment.put方法,因为7所存储的Segment和3、4不同,因此,不会阻塞在lock():



以上就是ConcurrentHashMap的工作机制,通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。
java.util.concurrent包还提供了设计用于多线程上下文中的Collection 实现:

ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList 和CopyOnWriteArraySet。当期望许多线程访问一个给定collection 时,ConcurrentHashMap 通常优于同步的HashMap,ConcurrentSkipListMap 通常优于同步的TreeMap。当期望的读数和遍历远远大于列表的更新数时,CopyOnWriteArrayList 优于同步的ArrayList。

/*
 * 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("AA");
      list.add("BB");
      list.add("CC");
   }

   @Override
   public void run() {
    
       Iterator<String> it = list.iterator();
    
       while(it.hasNext()){
           System.out.println(it.next());
        
           list.add("AA");
       }
   }
}

闭锁:CountDownLatch 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
闭锁可以延迟线程的进度直到其到达终止状态,闭锁可以用来确保某些活动直到其他活动都完成才继续执行:

  • 确保某个计算在其需要的所有资源都被初始化之后才继续执行;
  • 确保某个服务在其依赖的所有其他服务都已经启动之后才启动;
  • 等待直到某个操作所有参与者都准备就绪再继续执行。
/*
 * CountDownLatch :闭锁,在完成某些运算是,只有其他所有线程的运算全部完成,当前运算才继续执行
*/
public class TestCountDownLatch {

public static void main(String[] args) {
    final CountDownLatch latch = new CountDownLatch(50);
    LatchDemo ld = new LatchDemo(latch);

    long start = System.currentTimeMillis();

    for (int i = 0; i < 50; i++) {
        new Thread(ld).start();
    }

    try {
        latch.await();
    } catch (InterruptedException e) {
    }

    long end = System.currentTimeMillis();

    System.out.println("耗费时间为:" + (end - start));
   }

 }

class LatchDemo implements Runnable {

    private CountDownLatch latch;

    public LatchDemo(CountDownLatch latch) {
        this.latch = latch;
   }

   @Override
   public void run() {

      try {
        for (int i = 0; i < 50000; i++) {
            if (i % 2 == 0) {
                System.out.println(i);
            }
        }
    } finally {
        latch.countDown();
    }

}

}

相关文章

网友评论

    本文标题:JUC线程高级---ConcurrentHashMap和闭锁

    本文链接:https://www.haomeiwen.com/subject/solxsftx.html