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