`
javaso
  • 浏览: 53240 次
  • 性别: 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,保证了数据的不变性。每当进行修改和删除的时候,首先判断是否在同一段内,只要不在同一段内,都可以进行并发的操作。

相关推荐

    多线程并行执行,汇总结果

    Java提供了多种线程安全的集合,如`ConcurrentHashMap`、`AtomicInteger`等,它们在多线程环境下能够保证数据的一致性和完整性。线程可以在执行过程中将计算结果放入这些线程安全的数据结构,而无需担心数据竞争的...

    java多线程的讲解和实战

    8. **并发集合类**:Java提供了并发安全的集合类,如`ConcurrentHashMap`, `CopyOnWriteArrayList`, `BlockingQueue`等,它们内部实现了线程安全的算法,可以在多线程环境下高效使用。 9. **线程中断**:`interrupt...

    java多线程设计模式_java_设计模式_多线程_多线程课题_

    Java提供了一些线程安全的集合类,如ConcurrentHashMap、CopyOnWriteArrayList和CopyOnWriteArraySet,它们在多线程环境下提供了高并发的访问性能。 九、死锁检测与避免 死锁是多线程编程中的常见问题,两个或多个...

    多线程面试题

    在Java编程领域,多线程是面试中常见且重要的知识点,尤其对于系统设计和高并发处理的岗位至关重要。本文将围绕“多线程面试题”这一主题,深入探讨相关概念、技术及其应用。 1. **线程的概念**:线程是程序执行的...

    java 多线程编程实战指南(核心 + 设计模式 完整版)

    《Java多线程编程实战指南》这本书深入浅出地讲解了Java多线程的核心概念和实战技巧,分为核心篇和设计模式篇,旨在帮助开发者掌握并应用多线程技术。 1. **线程基础** - **线程的创建**:Java提供了两种创建线程...

    JAVA多线程编程技术PDF

    在Java编程领域,多线程是一项至关重要的技术,它允许程序同时执行多个任务,从而提高系统资源的利用率和程序的响应速度。这份“JAVA多线程编程技术PDF”是学习和掌握这一领域的经典资料,涵盖了多线程的全部知识点...

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

    【并发容器的线程安全性】与`HashMap`不同,`ConcurrentHashMap`通过采用非阻塞算法(如CAS操作)和分段锁机制来保证并发性能,避免了整个表的锁定,提高了在多线程环境下的并发性和性能。 【存储结构】`...

    多线程,高并发.zip

    在IT领域,多线程和高并发是两个关键概念,特别是在Java编程中,它们对于构建高效、可扩展的系统至关重要。下面将详细解释这两个概念及其在Java中的实现和应用。 多线程是指在一个应用程序中同时运行多个独立的执行...

    Java多线程练习题

    Java提供了一系列并发容器,如ConcurrentHashMap、CopyOnWriteArrayList等,它们内部实现了线程安全,能够在多线程环境下高效地使用。 八、死锁 当两个或更多线程互相等待对方释放资源而无法继续执行时,就会发生...

    Java多线程矩阵相乘的代码

    在Java编程语言中,多线程是实现并发执行任务的关键技术。这个压缩包中的内容,"Java多线程矩阵相乘的代码",显然提供了一个示例,演示如何利用多线程来加速矩阵乘法这一计算密集型操作。矩阵相乘在科学计算、图像...

    poi多线程大数据导出excel文件.zip

    本项目“poi多线程大数据导出excel文件”提供了一个解决方案,利用多线程来提高Excel的大数据导出效率。 Apache POI 3.1版本是较早的版本,而项目中使用了更新的4.1版本,这意味着它可能利用了更多优化和新特性。在...

    多线程技术大全.电子书

    9. **线程安全的数据结构**:某些数据结构(如Java的ConcurrentHashMap)设计为线程安全,可以在多线程环境下直接使用,无需额外的同步措施。 10. **线程局部存储**:线程局部变量只对创建它的线程可见,这样可以在...

    java多线程控制的赛跑程序

    在Java编程语言中,多线程是实现并发执行任务的关键技术。这个“java多线程控制的赛跑程序”是一个示例,展示了如何利用多线程来模拟一场赛跑比赛。在这个程序中,每个参赛者(线程)都有自己的运行逻辑,通过线程的...

    多线程示例.rar

    在IT领域,多线程是程序设计中的一个重要概念,尤其在服务器端开发、实时系统以及高性能计算中扮演着核心角色。多线程允许一个应用程序同时执行多个不同的任务,提高资源利用率,实现高效的并发处理。本压缩包“多...

    【JAVA多线程】多线程编程核心技术学习资料

    Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在现代计算机系统中,多线程技术尤其关键,因为它们能够充分利用多核处理器的能力。这份"Java多线程编程...

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

    这个方法确保在多线程环境下安全地创建哈希表。在源码中,`sizeCtl`变量扮演着关键角色,它的值有多种含义: 1. `-1`表示有一个线程正在创建哈希表。 2. `-N`表示有`N-1`个线程正在进行表复制(扩容时发生)。 3. ...

    多线程的实验

    "多线程.pdf"很可能包含更详细的理论解释和案例分析,可能涵盖了线程优先级、线程生命周期(新建、就绪、运行、阻塞、死亡)、线程安全的数据结构(如ConcurrentHashMap)以及高级特性如线程局部变量(ThreadLocal)...

    java多线程设计

    在Java编程中,多线程设计是实现高效并发处理的关键技术。它允许程序中的多个执行单元(线程)同时运行,提高系统资源利用率并优化性能。本知识点将深入探讨Java多线程设计以及如何利用“不可变对象”(immutable ...

    精通java多线程

    Java的并发集合库(java.util.concurrent包)提供了线程安全的集合类,如ConcurrentHashMap、CopyOnWriteArrayList和ConcurrentLinkedQueue等,它们在多线程环境下能确保数据的一致性和安全性。 十、异常处理 在多...

Global site tag (gtag.js) - Google Analytics