众所周知hashMap 是线程不安全的,在多线程访问的情况下,要做同步的处理
ConcurrentHashMap是Java 5中支持高并发、高吞吐量的线程安全HashMap实现
ConcurrentHashMap get() 总能拿到最新的值,类似于关键字 volatile保证100%读取到最新的数据
如下用代码说明:
package com.iteye.javaso.demo;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CopyOfConCurrentHashMapThreadTest2 {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
public static void main(String args[]) {
CopyOfConCurrentHashMapThreadTest2 test = new CopyOfConCurrentHashMapThreadTest2();
Runnable sleep = new ThreadSleep2(test, "第一条线程");
ThreadSecond2 charge2 = new ThreadSecond2(test, "改变值的第2线程");
ThreadSecond2 charge3 = new ThreadSecond2(test, "改变值的第3线程");
ThreadSecond2 charge4 = new ThreadSecond2(test, "改变值的第4线程");
ThreadSecond23 chargeXX = new ThreadSecond23(test, "改变值的XXXX线程");
ExecutorService exc = Executors.newFixedThreadPool(5);
exc.execute(sleep);
exc.execute(charge3);
exc.execute(charge2);
exc.execute(chargeXX);
exc.execute(charge4);
exc.shutdown();
System.out.println("洗洗睡吧----------------");
try {
Thread.sleep(16000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("多个线程后,最终运行结果:" + test.map.get("firstKey"));
}
public void put(String value, int state) {
map.put("firstKey", value);
// Thread thread= Thread.currentThread();
if (state == 0) {
System.out.println("开始睡觉了--------------");
try {
Thread.sleep(4000);
System.out.println("睡醒了-------");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class ThreadSleep2 extends Thread {
ConcurrentHashMap<String, String> map;
public ThreadSleep2(ConcurrentHashMap<String, String> map, String threadName) {
this.map = map;
this.name = threadName;
}
CopyOfConCurrentHashMapThreadTest2 test;
public ThreadSleep2(CopyOfConCurrentHashMapThreadTest2 test,
String threadName) {
super(threadName);
this.test = test;
this.name = threadName;
}
@Override
public void run() {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
System.out.println("---------------进入第一条线程-----睡十秒先--------");
System.out.println("第一条线程未设置前值为:*** " + test.map.get("firstKey"));
test.put(name, 0);
System.out.println("第一条线程执行完毕 Map中值为:" +test.map.get("firstKey"));
}
String name = "";
public String toString() {
return "当前线程的名字是:" + name;
}
}
class ThreadSecond2 extends Thread {
ConcurrentHashMap<String, String> map;
public ThreadSecond2(ConcurrentHashMap<String, String> map,
String threadName) {
super(threadName);
this.map = map;
this.name = threadName;
}
CopyOfConCurrentHashMapThreadTest2 test;
public ThreadSecond2(CopyOfConCurrentHashMapThreadTest2 test,
String threadName) {
super(threadName);
this.test = test;
this.name = threadName;
}
@Override
public void run() {
System.out.println("-----------进入其它线程---------");
System.out.println("当前线程是:" + this.name + " 未设置map前值为:"
+ test.map.get("firstKey"));
test.put(name, 2);
System.out.println("hashMap中 firstKey值为:" + name);
}
String name = "";
public String toString() {
return "当前线程的名字是:" + name;
}
}
class ThreadSecond23 extends Thread {
ConcurrentHashMap<String, String> map;
public ThreadSecond23(ConcurrentHashMap<String, String> map,
String threadName) {
super(threadName);
this.map = map;
this.name = threadName;
}
CopyOfConCurrentHashMapThreadTest2 test;
public ThreadSecond23(CopyOfConCurrentHashMapThreadTest2 test,
String threadName) {
super(threadName);
this.test = test;
this.name = threadName;
}
@Override
public void run() {
System.out.println("-----------进入XXXXXXX线程---------");
System.out.println("当前线程是:" + Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
test.put(name, 2);
System.out.println("hashMap中 firstKey值为:" + name);
}
String name = "";
public String toString() {
return "当前线程的名字是:" + name;
}
}
---------------进入第一条线程-----睡十秒先--------
-----------进入其它线程---------
第一条线程未设置前值为:*** null
当前线程是:改变值的第2线程 未设置map前值为:null
hashMap中 firstKey值为:改变值的第2线程
洗洗睡吧----------------
开始睡觉了--------------
-----------进入其它线程---------
-----------进入其它线程---------
当前线程是:改变值的第4线程 未设置map前值为:改变值的第2线程
-----------进入XXXXXXX线程---------
当前线程是:pool-1-thread-4
当前线程是:改变值的第3线程 未设置map前值为:改变值的第2线程
hashMap中 firstKey值为:改变值的第3线程
hashMap中 firstKey值为:改变值的第4线程
hashMap中 firstKey值为:改变值的XXXX线程
睡醒了-------
第一条线程执行完毕 Map中值为:改变值的XXXX线程
多个线程后,最终运行结果:改变值的XXXX线程
最高优先级的线程:ThreadSleep2 put 值后,进入睡眠,由于未进行同步处理,这时其它线程开始执行,改变了map中firstKey值,到最先执行的线程醒来后,输出map中firstKey值已被其它线程改变:改变值的XXXX线程, 可见get() 总能拿到最新的值,类似于关键字 volatile保证100%读取到最新的数据.
对put方法,进行同步后:
public synchronized void put(String value, int state) {
map.put("firstKey", value);
// Thread thread= Thread.currentThread();
if (state == 0) {
System.out.println("开始睡觉了--------------");
try {
Thread.sleep(4000);
System.out.println("睡醒了-------");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
synchronized (test) {
test.put(name, 0);
System.out.println("第一条线程执行完毕 Map中值为:" +test.map.get("firstKey"));
}
输出:
---------------进入第一条线程-----睡十秒先--------
第一条线程未设置前值为:*** null
开始睡觉了--------------
洗洗睡吧----------------
-----------进入其它线程---------
-----------进入其它线程---------
当前线程是:改变值的第3线程 未设置map前值为:第一条线程
当前线程是:改变值的第2线程 未设置map前值为:第一条线程
-----------进入XXXXXXX线程---------
当前线程是:pool-1-thread-4
-----------进入其它线程---------
当前线程是:改变值的第4线程 未设置map前值为:第一条线程
睡醒了-------
第一条线程执行完毕 Map中值为:第一条线程
hashMap中 firstKey值为:改变值的XXXX线程
hashMap中 firstKey值为:改变值的第2线程
hashMap中 firstKey值为:改变值的第3线程
hashMap中 firstKey值为:改变值的第4线程
多个线程后,最终运行结果:改变值的第3线程
其它线程要等待sleep线程释放锁,至第一条线程执行完毕时,map值为:sleep线程 put的值:第一条线程
结论ConcurrentHashMap put操作需要做同步,get操作不需要
分享到:
相关推荐
解析concurrenthashmap的源码,学习多线程的思想
阿里面试题:ConcurrentHashMap为什么是线程安全的? ConcurrentHashMap,其实是线程安全的HashMap,所以阅读ConcurrentHashMap,建议 先阅读一下两篇介绍HashMap的文章 你真的懂大厂面试题:HashMap吗? jdk1.7 ...
Java 多线程与并发(13_26)-JUC集合_ ConcurrentHashMap详解
HashTable是一个线程安全的类,它使用synchronized来锁住整张Hash表来实现线程安全,即每次锁住整张表让线程独占,相当于所有线程进行读写时都去竞争一把锁,导致效率非常低下。ConcurrentHashMap可以做到读取数据不...
并发集合:JUC提供了一些线程安全的集合类,如ConcurrentHashMap、ConcurrentLinkedQueue等,可以在多线程环境下安全地访问和修改集合。 原子操作:JUC提供了一些原子操作类,如AtomicInteger、AtomicLong等,可以...
服务器,客户端都是多线程的服务器ConcurrentHashMap <客户端,套接字通道>由多个客户端共享客户输入和侦听线程共享LinkedBlockingQueue ConcurrentHashMap 与上面相同Nio工具内部多线程安全异常处理一般的对于...
Java并发编程学习宝典(漫画版),Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习...
【2018最新最详细】并发多线程教程,课程结构如下 1.并发编程的优缺点 2.线程的状态转换以及基本操作 3.java内存模型以及happens-before规则 4.彻底理解synchronized 5.彻底理解volatile 6.你以为你真的了解final吗...
Java并发编程学习宝典(漫画版),Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习...
ConcurrentHashMap使用了分段锁(Segment)来实现并发的读写操作,每个Segment都相当于一个小的HashMap,将整个哈希表分成多个部分。这样可以同时进行多个线程的并发读写操作,不会阻塞其他线程的访问。 需要注意的...
1.1为什么需要多线程 1.2不安全示例 1.3并发问题的根源 1.4JMM 1.5线程安全的分类 1.6线程安全的方法 二、线程基础 2.1状态 2.2使用方式 2.3基础机制 2.4中断 2.5互斥同步 2.6线程合作 三、...
java多线程文档,锁,并发锁,hashmap,concurrenthashmap
对JDK8中ConcurrentHashMap的容器初始化、添加元素安全、扩容安全以及多线程情况下扩容效率的提高、集合长度的累计方式以及获取集合长度等这些方法的源码进行了详细的解释说明
只是都是相通的,当我们了解了ConcurrentHashMap的实现原理以及各个方法的实现机制,我们对于其他的hash类型实现也能快速...整个transfer的代码还是有些晦涩难懂的,因为这个方法本身是支持多线程的,也就是多线程迁移
第一步是用单线程构建一个2倍容量的nextTable 第二步就是用多线程去遍历table里面所有的Node 第三步,当所有数据都复制到nextTable之后,将
HashMap 和 Hashtable 的区别,HashSet如何检查重复,HashMap的底层实现,HashMap 多线程操作导致死循环问题,ConcurrentHashMap 和 Hashtable 的区别,ConcurrentHashMap线程安全的具体实现⽅式/底层具体实现,...
多线程中的常见问题 同步关键字原理 多线程的三大核心 对锁的一些认知 ReentrantLock实现原理 ConcurrentHashMap 的实现原理 如何优雅地使用和理解线程池 深入理解线程通信 一个线程召集的诡异事件 线程池中你不可...
在JDK的并发包里提供了几个非常有用的并发容器和并发工具类,供我们在多线程开发中进行使用。 并发包的来历: 在实际开发中如果不需要考虑线程安全问题,大家不需要做线程安全,因为如果做了反而性能不好! 但是开发...
hashmap如何解决hash冲突,为什么hashmap中的链表需要转成红黑树?...ConcurrentHashMap是如何让多线程同时参与扩容? LinkedBlockingQueue、DelayQueue是如何实现的? CopyOnWriteArrayList是如何保证线程安全的?
4. 多线程程序需要注意事项 6 二、认识Java里的线程 7 1. Java程序天生就是多线程的 7 2. 线程的启动与中止 7 3. 对Java里的线程再多一点点认识 8 三、线程间的共享和协作 9 1. 线程间的共享 9 2. ThreadLocal辨析 ...