JAVA-JDK1.7-ConCurrentHashMap-测试和验证
概述
上次记录了关于ConCurrentHashMap的原理以及源码,现在我对其进行有关功能的测试,下面就讲解一下我测试的内容和代码。这些测试主要针对JDK1.7版本。
GET安全测试
上一篇写过get方法是没有加锁的,因为HashEntry的value和next属性是volatile的,volatile直接保证了可见性,所以读的时候可以不加锁,现在写一个程序,启动20个线程,只有一个key="count",每个线程都要执行 map.put(key, 1) 或者 map.put(key, value + 1) ,所以理论上说,20个线程会得到值("count",20),所有的源码如下:
1 package test;
2
3 import java.io.Serializable;
4 import java.util.concurrent.ConcurrentHashMap;
5 import java.util.concurrent.ExecutorService;
6 import java.util.concurrent.Executors;
7 import java.util.concurrent.locks.ReentrantLock;
8
9 /**
10 * Created by Administrator on 2019/12/4.
11 */
12 public class TestConcurrentHashMap {
13
14
15 public static void main(String[] args) {
16 DoWork dw = new DoWork(map);
17 //map.put("1",1);
18 ExecutorService pool = Executors.newFixedThreadPool(8);
19 try {
20 for (int i = 0; i < 20; i++) {
21 pool.execute(new Thread(dw));// 开启20个线程
22 }
23 Thread.sleep(5000);// 主线程睡眠5s 等待子线程完成任务
24 } catch (Exception e) {
25 e.printStackTrace();
26 } finally {
27 pool.shutdown();// 关闭线程池
28 }
29 System.out.println("统计的数量:" + map.get("count"));
30
31 }
32 private static ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();
33
34 static class DoWork extends ReentrantLock implements Serializable,Runnable {
35
36 private ConcurrentHashMap<String, Integer> map = null;
37
38 public DoWork(ConcurrentHashMap<String, Integer> map) {
39 this.map = map;
40 }
41
42 @Override
43 public void run() {
44 add("count");
45 }
46
47 public void add(String key) {
48 Integer value = map.get(key);// 获取map中的数值
49 System.out.println("当前数量" + value);
50 if (null == value) {
51 map.put(key, 1);// 第一次存放
52 } else {
53 map.put(key, value + 1);// 以后次存放
54 }
55 }
56 public void addLock(String key) {
57 lock();
58 try {
59 Integer value = map.get(key);
60 System.out.println("当前数量" + value);
61 if (null == value) {
62 map.put(key, 1);
63 } else {
64 map.put(key, value + 1);
65 }
66 } finally {
67 unlock();
68 }
69 }
70
71
72
73 }
74
75 }
在如上测试代码中有如下问题:
问题1:为什么开启20个线程,启动的线程池确是8个 见第18行 21行代码?
回答:这样可以更大的概率实现线程并发。也就是更容易出现问题。
问题2:为什么要睡眠5s,
回答:那是因为统计结果的时候尽量确认所有线程执行完了,结果更加准确。
问题3:ReentrantLock 方法是干嘛的?
回答:ReentrantLock实现了独占功能,是这里使用的原因。
当在线程run方法中执行add(String key)方法时候,执行结果如下:
明显有问题的说,put是有锁的,所以先猜测get存在不安全的嫌疑,现在查看get方法源码,说明get确实没有加锁。所以说明的问题是虽然put有原子性,但是get+put就没有原子性,也就是说,当第一个线程get一个值之后,还没有put进去的时候,就被第二个线程get了,所以第二个线程get的值就是第一个线程put之前的值。
1 public V get(Object key) {
2 Segment<K,V> s; // manually integrate access methods to reduce overhead
3 HashEntry<K,V>[] tab;
4 int h = hash(key);
5 long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
6 if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
7 (tab = s.table) != null) {
8 for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
9 (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
10 e != null; e = e.next) {
11 K k;
12 if ((k = e.key) == key || (e.hash == h && key.equals(k)))
13 return e.value;
14 }
15 }
16 return null;
17 }
现在对add方法执行加锁方法,执行测试代码的56行代码的addLock方法。
然后debug输出是:
并发效率测试
现在模拟1000个并发,每个测试1000次操作,循环测试10轮。分别测试Put和Get操作,测试对象HashMapSync、ConcurrentHashMap、Hashtable。源码如下:
1 package test;
2 import java.util.Collections;
3 import java.util.HashMap;
4 import java.util.Hashtable;
5 import java.util.Map;
6 import java.util.concurrent.ConcurrentHashMap;
7
8 import static javafx.scene.input.KeyCode.T;
9
10
11 /**
12 * 测试HashMap和ConcurrentHashMap的并发性能差别。
13 *
14 *
15 */
16 public class TestConCurrent {
17 static final int threads = 1000;
18 static final int NUMBER = 1000;
19
20 public static void main(String[] args) throws Exception {
21 Map<String, Integer> hashmapSync = Collections
22 .synchronizedMap(new HashMap<String, Integer>());
23 Map<String, Integer> concurrentHashMap = new ConcurrentHashMap<String, Integer>();
24 Map<String, Integer> hashtable = new Hashtable<String, Integer>();
25 long totalA = 0;
26 long totalB = 0;
27 long totalC = 0;
28 for (int i = 0; i <= 10; i++) {
29 totalA += testPut(hashmapSync);
30 totalB += testPut(concurrentHashMap);
31 totalC += testPut(hashtable);
32 }
33 System.out.println("Put time HashMapSync=" + totalA + "ms.");
34 System.out.println("Put time ConcurrentHashMap=" + totalB + "ms.");
35 System.out.println("Put time Hashtable=" + totalC + "ms.");
36 totalA = 0;
37 totalB = 0;
38 totalC = 0;
39 for (int i = 0; i <= 10; i++) {
40 totalA += testGet(hashmapSync);
41 totalB += testGet(concurrentHashMap);
42 totalC += testGet(hashtable);
43 }
44 System.out.println("Get time HashMapSync=" + totalA + "ms.");
45 System.out.println("Get time ConcurrentHashMap=" + totalB + "ms.");
46 System.out.println("Get time Hashtable=" + totalC + "ms.");
47 }
48 public static long testPut(Map<String, Integer> map) throws Exception {
49 long start = System.currentTimeMillis();
50 for (int i = 0; i < threads; i++) {
51 new MapPutThread(map).start();
52 }
53 while (MapPutThread.counter > 0) {
54 Thread.sleep(1);
55 }
56 return System.currentTimeMillis() - start;
57 }
58 public static long testGet(Map<String, Integer> map) throws Exception {
59 long start = System.currentTimeMillis();
60 for (int i = 0; i < threads; i++) {
61 new MapGetThread(map).start();
62 }
63 while (MapGetThread.counter > 0) {
64 Thread.sleep(1);
65 }
66 return System.currentTimeMillis() - start;
67 }
68 }
69 class MapPutThread extends Thread {
70 static int counter = 0;
71 static Object lock = new Object();
72 private Map<String, Integer> map;
73 private String key = this.getId() + "";
74 MapPutThread(Map<String, Integer> map) {
75 synchronized (lock) {
76 counter++;
77 }
78 this.map = map;
79 }
80 public void run() {
81 for (int i = 1; i <= TestConCurrent.NUMBER; i++) {
82 map.put(key, i);
83 }
84 synchronized (lock) {
85 counter--;
86 }
87 }
88 }
89 class MapGetThread extends Thread {
90 static int counter = 0;
91 static Object lock = new Object();
92 private Map<String, Integer> map;
93 private String key = this.getId() + "";
94 MapGetThread(Map<String, Integer> map) {
95 synchronized (lock) {
96 counter++;
97 }
98 this.map = map;
99 }
100 public void run() {
101 for (int i = 1; i <= TestConCurrent.NUMBER; i++) {
102 map.get(key);
103 }
104 synchronized (lock) {
105 counter--;
106 }
107 }
108 }
如上代码只是测试效率的简单测试:
测试结果是:
总结
能动手的尽量不要猜,能用代码的尽量不要相信原理。
感谢网络大神,参考链接:
https://blog.csdn.net/java2000_net/article/details/3373181
https://www.cnblogs.com/yanphet/p/5726919.html
JAVA-JDK1.7-ConCurrentHashMap-测试和验证的更多相关文章
- dubbox部署到jdk1.7环境,启动:java.lang.NoSuchMethodError: java.util.concurrent.ConcurrentHashMap.keySet()
本地用jdk1.8编译的服务提供端war包,部署到环境报错了: INFO: Initializing Spring root WebApplicationContext [16/08/17 05:14 ...
- Java JDK1.5、1.6、1.7新特性整理(转)
原文链接:http://www.cnblogs.com/tony-yang-flutter/p/3503935.html 一.Java JDK1.5的新特性 1.泛型: List<String& ...
- Java JDK1.5、1.6、1.7新特性整理
转载请注明出处:http://www.cnblogs.com/tony-yang-flutter 一.Java JDK1.5的新特性 1.泛型: List<String> strs = n ...
- linux环境下安装jdk(本文示例是jdk1.6.0_export JAVA_HOME=/usr/java/jdk1.6.0_45 export PATH=$JAVA_HOME/bin:$PATH export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar45)
第一步:创建一个文件夹安装jdk(虽说地址一般自定义,但是为了方便查找请按照笔者建议目录 ):/usr/java 将jdk-6u45-linux-x64.bin文件放到 /usr/java 文件夹 ...
- win10 如何配置 java jdk1.8环境变量(2017.2.24)
win10 如何配置 java jdk 环境变量 这里的win10 为全新安装的系统 一.安装 下载 jdk 64位 windows 版本安装(默认安装) 默认安装的路径: C:\Program Fi ...
- 安装JDK出现错误:-bash: /usr/java/jdk1.7.0_71/bin/java: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory解决办法
1.错误描述:安装好jdk之后,通过java -version,javac,java等命令测试是否安装成功时出现错误-bash: /usr/java/jdk1.7.0_71/bin/java: /li ...
- 死磕 java集合之ConcurrentHashMap源码分析(三)
本章接着上两章,链接直达: 死磕 java集合之ConcurrentHashMap源码分析(一) 死磕 java集合之ConcurrentHashMap源码分析(二) 删除元素 删除元素跟添加元素一样 ...
- Java工具类——通过配置XML验证Map
Java工具类--通过配置XML验证Map 背景 在JavaWeb项目中,接收前端过来的参数时通常是使用我们的实体类进行接收的.但是呢,我们不能去决定已经搭建好的框架是怎么样的,在我接触的框架中有一种 ...
- .net 客户端调用java或.net webservice进行soapheader验证
.net 客户端调用java或.net webservice进行soapheader验证 最近项目中有业务需要跨平台调用web服务,客户端和服务器之间采用非对称加密来保证数据的安全性,webservi ...
- Mockito:一个强大的用于Java开发的模拟测试框架
https://blog.csdn.net/zhoudaxia/article/details/33056093 介绍 本文将介绍模拟测试框架Mockito的一些基础概念, 介绍该框架的优点,讲解应用 ...
随机推荐
- [BUUCTF]REVERSE——[BJDCTF2020]BJD hamburger competition
[BJDCTF2020]BJD hamburger competition 附件 步骤: 例行检查,64位程序,无壳儿 由于unity是用C++开发的,这里就不用IDA了,直接用dnspy看源码 在B ...
- CF1059A Cashier 题解
Content 定义一天长度为 \(L\),每次休息的时间为 \(a\).一天会有 \(n\) 个客人到访,第 \(i\) 个客人会在 \(t_i\) 的时刻到访,会停留 \(l_i\) 的时间.只有 ...
- java 图形化工具Swing 基本使用
Swing介绍: 使用Swing开发图形界面比AWT更加优秀,因为Swing是一种轻量级组件,它采用100% Java实现,不再依赖于本地平台的图形界面,所以可以在所有平台上保持相同的运行效果,对跨平 ...
- flexpaper上传带中文名字的文档,在页面显示若出现404错误时,请在server.xml文件中进行编码utf-8
flexpaper上传带中文名字的文档,在页面显示若出现404错误时,请在server.xml文件中进行编码utf-8
- canvas 实现渐变色填充的三角形
实现效果 效果一: 效果二: 实现思路 canvas实现 1. 绘制三角形 // html <canvas id="triangle" width="30" ...
- JAVA实现websocket客户端
pom依赖 <dependency> <groupId>org.java-websocket</groupId> <artifactId>Java-We ...
- 【LeetCode】362. Design Hit Counter 解题报告 (C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 字典 日期 题目地址:https://leetcode ...
- 【LeetCode】437. Path Sum III 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 DFS + DFS BFS + DFS 日期 题目地 ...
- 【LeetCode】807. Max Increase to Keep City Skyline 解题报告(Python &C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 1002 - Country Roads(light oj)
1002 - Country Roads I am going to my home. There are many cities and many bi-directional roads betw ...