java并发初探ConcurrentHashMap

Doug Lea在java并发上创造了不可磨灭的功劳,ConcurrentHashMap体现这位大师的非凡能力。

1.8中ConcurrentHashMap的线程安全

1.volatile Node<k,v> []table保证数组的可见性

2.get操作没有加锁

3.put操作调用final V putVal(K key, V value, boolean onlyIfAbsent) ,在方法内部为Syncronized方法加锁,Syncronized据说在1.8得到优化

4.扩容的方法不是Syncronized,而在数据迁移的时候通过Syncronized迁移数据

5.多线程putVal(K key, V value, boolean onlyIfAbsent),通过helpTransfer帮助数组扩容(binCount),然后继续添加元素 (binCount!=0跳出)

            else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);

6.多线程下扩容,因为扩容是多线程共同进行,而且锁住了首节点,能够快速扩容

            else if ((f = tabAt(tab, i)) == null)//锁住节点
advance = casTabAt(tab, i, null, fwd);
else if ((fh = f.hash) == MOVED)
advance = true; // already processed
else {
//执行该节点的扩容数据移动
synchronized (f) {

7.ConcurrentHashMap取消了Segment分段锁,采用CAS和synchronized来保证并发安全。数据结构跟HashMap1.8的结构类似,数组+链表/红黑二叉树。Java 8在链表长度超过一定阈值(8)时将链表(寻址时间复杂度为O(N))转换为红黑树(寻址时间复杂度为O(log(N)))

synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。

例子

package com.java.javabase.thread.collection;

import com.java.javabase.innerclass.DoThis;
import lombok.extern.slf4j.Slf4j; import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; /**
* @author
*/
@Slf4j
public class ConcurrentHashMapTest {
public static int cap = 5;
public static ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>();
//public static HashMap<Integer, String> map = new HashMap<>();//会出现ConcurrentModificationException
public static void main(String[] args) {
InnerThread t1= new InnerThread("t1");
InnerThread t2= new InnerThread("t2");
t1.start();
t2.start();
//printAll(map);
}
static class InnerThread extends Thread {
public InnerThread(String name)
{
super(name);
}
@Override
public void run() {
for (int i = 0; i < cap; i++) {
try {
map.put(i, String.valueOf(i));
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} printAll(map);
}
}
} static void printAll(Map<Integer, String> map) {
//Set<Map.Entry<Integer, String>> entrySet=map.entrySet();
Set entrySet = map.entrySet();
Iterator<Map.Entry<Integer, String>> it = entrySet.iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
log.info("thread {}: ,key {} value {}", Thread.currentThread().getName(),
entry.getKey(), entry.getValue());
}
}
}

java并发初探ConcurrentHashMap的更多相关文章

  1. java并发初探ConcurrentSkipListMap

    java并发初探ConcurrentSkipListMap ConcurrentSkipListMap以调表这种数据结构以空间换时间获得效率,通过volatile和CAS操作保证线程安全,而且它保证了 ...

  2. java并发初探ThreadPoolExecutor拒绝策略

    java并发初探ThreadPoolExecutor拒绝策略 ThreadPoolExecuter构造器 corePoolSize是核心线程池,就是常驻线程池数量: maximumPoolSize是最 ...

  3. java并发初探CyclicBarrier

    java并发初探CyclicBarrier CyclicBarrier的作用 CyclicBarrier,"循环屏障"的作用就是一系列的线程等待直至达到屏障的"瓶颈点&q ...

  4. java并发初探CountDownLatch

    java并发初探CountDownLatch CountDownLatch是同步工具类能够允许一个或者多个线程等待直到其他线程完成操作. 当前前程A调用CountDownLatch的await方法进入 ...

  5. java并发初探ReentrantWriteReadLock

    java并发初探ReentrantWriteReadLock ReenWriteReadLock类的优秀博客 ReentrantReadWriteLock读写锁详解 Java多线程系列--" ...

  6. Java并发容器--ConcurrentHashMap

    引子 1.不安全:大家都知道HashMap不是线程安全的,在多线程环境下,对HashMap进行put操作会导致死循环.是因为多线程会导致Entry链表形成环形数据结构,这样Entry的next节点将永 ...

  7. Java并发分析—ConcurrentHashMap

    LZ在 https://www.cnblogs.com/xyzyj/p/6696545.html 中简单介绍了List和Map中的常用集合,唯独没有CurrentHashMap.原因是CurrentH ...

  8. 深入理解Java并发容器——ConcurrentHashMap

    目录 重要属性和类 put 为什么java8后放弃分段锁,改用CAS和同步锁 初始化 addCount 扩容 树化 参考 重要属性和类 sizeCtl 容量控制标识符,在不同的地方有不同用途,而且它的 ...

  9. Java 并发实践 — ConcurrentHashMap 与 CAS

    转载 http://www.importnew.com/26035.html 最近在做接口限流时涉及到了一个有意思问题,牵扯出了关于concurrentHashMap的一些用法,以及CAS的一些概念. ...

随机推荐

  1. java 执行jar包里面一个类class文件

    一.环境: 1. linux 2. 有两个java类,A.java和B.java,都在同一个目录下 二.源码: A.java   package com.abc;   public class A { ...

  2. windows jdk8

    C:\Program Files (x86)\Java\jdk1.8.0_65 //JAVA_HOME .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.j ...

  3. 【MYSQL建库和建表】MYSQL建库和建表

    1.Navicat创建Mysql数据库 2.创建创建用户表和索引 CREATE TABLE `t_user` ( `id` ) NOT NULL AUTO_INCREMENT COMMENT '主键' ...

  4. spark实验(二)--eclipse安装scala环境(2)

    此次在eclipse中的安装参考这篇博客https://blog.csdn.net/lzxlfly/article/details/80728772 Help->Eclipse Marketpl ...

  5. 如何查看Ubuntu系统版本

    在Ubuntu终端,常用以下几种方式查看系统版本: 一.uname -a 二.cat /etc/issue 三.cat /etc/lsb-release 四.lsb_release -a 五.cat ...

  6. 走过的K8S坑

    基本的docker命令: docker 镜像 打包成文件 sudo docker save -o 打包后的文件名 {镜像ID}或者{镜像标签} docker 改名: docker tag ff2816 ...

  7. techiediaries网站的Laravel 6系列教程

    Laravel 6 Tutorial & New Features - Build a CRM [PART 1] Laravel 6 REST API CRUD Tutorial - Buil ...

  8. string类的具体实现

    bigThree,注意拷贝构造函数的写法. #ifndef __MYSTRING__ #define __MYSTRING__ class String { public: String(); Str ...

  9. python开发接口

    享一段代码,开发了3个接口:            1.上传文件            2.查看所有文件            3.下载文件 使用python开发,需要安装flask模块,使用pip ...

  10. GIT使用教程——命令详解

    $ git init 当前目录建立GIT可以管理的仓库(版本库),生成一个.git的隐藏文件夹 $ git add <filename> 将工作区的文件修改添加到版本库的暂存区 $ git ...