`
javaso
  • 浏览: 51907 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

ConcurrentHashMap&&多线程

    博客分类:
  • java
阅读更多

 众所周知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操作不需要  

 

 

 

 

 

 

 

 

4
3
分享到:
评论
2 楼 javaso 2011-06-06  
Technoboy 写道
引用
结论ConcurrentHashMap put操作需要做同步,get操作不需要 

原因在于,ConcurrentHashMap中使用了锁分离技术,也就是说,它用多个锁来控制对hash表不同部分的修改操作。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行,其也被定义为final,保证了数据的不变性。每当进行修改和删除的时候,首先判断是否在同一段内,只要不在同一段内,都可以进行并发的操作。


thanks
1 楼 Technoboy 2011-06-03  
引用
结论ConcurrentHashMap put操作需要做同步,get操作不需要 

原因在于,ConcurrentHashMap中使用了锁分离技术,也就是说,它用多个锁来控制对hash表不同部分的修改操作。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行,其也被定义为final,保证了数据的不变性。每当进行修改和删除的时候,首先判断是否在同一段内,只要不在同一段内,都可以进行并发的操作。

相关推荐

    ConcurrentHashMap源码解析

    解析concurrenthashmap的源码,学习多线程的思想

    阿里面试题:ConcurrentHashMap为什么是线程安全的?

    阿里面试题:ConcurrentHashMap为什么是线程安全的? ConcurrentHashMap,其实是线程安全的HashMap,所以阅读ConcurrentHashMap,建议 先阅读一下两篇介绍HashMap的文章 你真的懂大厂面试题:HashMap吗? jdk1.7 ...

    Java 多线程与并发(13-26)-JUC集合- ConcurrentHashMap详解.pdf

    Java 多线程与并发(13_26)-JUC集合_ ConcurrentHashMap详解

    Java并发编程笔记之ConcurrentHashMap原理探究.docx

    HashTable是一个线程安全的类,它使用synchronized来锁住整张Hash表来实现线程安全,即每次锁住整张表让线程独占,相当于所有线程进行读写时都去竞争一把锁,导致效率非常低下。ConcurrentHashMap可以做到读取数据不...

    JUC多线程学习个人笔记

    并发集合:JUC提供了一些线程安全的集合类,如ConcurrentHashMap、ConcurrentLinkedQueue等,可以在多线程环境下安全地访问和修改集合。 原子操作:JUC提供了一些原子操作类,如AtomicInteger、AtomicLong等,可以...

    nio-chatroom:基于Java Nio的单服务器多客户端聊天室

    服务器,客户端都是多线程的服务器ConcurrentHashMap &lt;客户端,套接字通道&gt;由多个客户端共享客户输入和侦听线程共享LinkedBlockingQueue ConcurrentHashMap 与上面相同Nio工具内部多线程安全异常处理一般的对于...

    25 经典并发容器,多线程面试必备—深入解析ConcurrentHashMap下.pdf

    Java并发编程学习宝典(漫画版),Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习...

    【2018最新最详细】并发多线程教程

    【2018最新最详细】并发多线程教程,课程结构如下 1.并发编程的优缺点 2.线程的状态转换以及基本操作 3.java内存模型以及happens-before规则 4.彻底理解synchronized 5.彻底理解volatile 6.你以为你真的了解final吗...

    24 经典并发容器,多线程面试必备。—深入解析ConcurrentHashMap.pdf

    Java并发编程学习宝典(漫画版),Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习...

    java集合-ConcurrentHashMap的使用

    ConcurrentHashMap使用了分段锁(Segment)来实现并发的读写操作,每个Segment都相当于一个小的HashMap,将整个哈希表分成多个部分。这样可以同时进行多个线程的并发读写操作,不会阻塞其他线程的访问。 需要注意的...

    Java多线程和并发知识整理

    1.1为什么需要多线程 1.2不安全示例 1.3并发问题的根源 1.4JMM 1.5线程安全的分类 1.6线程安全的方法 二、线程基础 2.1状态 2.2使用方式 2.3基础机制 2.4中断 2.5互斥同步 2.6线程合作 三、...

    多线程文档.zip

    java多线程文档,锁,并发锁,hashmap,concurrenthashmap

    JDK1.8ConcurrentHashMap.md

    对JDK8中ConcurrentHashMap的容器初始化、添加元素安全、扩容安全以及多线程情况下扩容效率的提高、集合长度的累计方式以及获取集合长度等这些方法的源码进行了详细的解释说明

    JDK1.8 ConcurrentHashMap的一点理解

    只是都是相通的,当我们了解了ConcurrentHashMap的实现原理以及各个方法的实现机制,我们对于其他的hash类型实现也能快速...整个transfer的代码还是有些晦涩难懂的,因为这个方法本身是支持多线程的,也就是多线程迁移

    71-ConcurrentHashMap笔记1

    第一步是用单线程构建一个2倍容量的nextTable 第二步就是用多线程去遍历table里面所有的Node 第三步,当所有数据都复制到nextTable之后,将

    Java集合框架完整说明便于了解集合

    HashMap 和 Hashtable 的区别,HashSet如何检查重复,HashMap的底层实现,HashMap 多线程操作导致死循环问题,ConcurrentHashMap 和 Hashtable 的区别,ConcurrentHashMap线程安全的具体实现⽅式/底层具体实现,...

    Java Core Sprout:基础、并发、算法

    多线程中的常见问题 同步关键字原理 多线程的三大核心 对锁的一些认知 ReentrantLock实现原理 ConcurrentHashMap 的实现原理 如何优雅地使用和理解线程池 深入理解线程通信 一个线程召集的诡异事件 线程池中你不可...

    多线程下的并发包:这些面试必问的,你都知道吗?

    在JDK的并发包里提供了几个非常有用的并发容器和并发工具类,供我们在多线程开发中进行使用。 并发包的来历: 在实际开发中如果不需要考虑线程安全问题,大家不需要做线程安全,因为如果做了反而性能不好! 但是开发...

    集合常见面试题

    hashmap如何解决hash冲突,为什么hashmap中的链表需要转成红黑树?...ConcurrentHashMap是如何让多线程同时参与扩容? LinkedBlockingQueue、DelayQueue是如何实现的? CopyOnWriteArrayList是如何保证线程安全的?

    并发编程笔记20190526.docx

    4. 多线程程序需要注意事项 6 二、认识Java里的线程 7 1. Java程序天生就是多线程的 7 2. 线程的启动与中止 7 3. 对Java里的线程再多一点点认识 8 三、线程间的共享和协作 9 1. 线程间的共享 9 2. ThreadLocal辨析 ...

Global site tag (gtag.js) - Google Analytics