`
六十三
  • 浏览: 44059 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java util之常用数据类型特性盘点(Map 四种同步方式的性能比较)

阅读更多

出处:http://www.iteye.com/topic/164644

 

 

  1. 使用 synchronized 关键字,这也是最原始的方法。代码如下 

     

    synchronized(anObject)
    {
    	value = map.get(key);
    }
     

     

     

  2. 使用 JDK1.5 提供的锁(java.util.concurrent.locks.Lock)。代码如下 

     

    lock.lock();
    value = map.get(key);
    lock.unlock();
     

     

     

  3. 实际应用中,可能多数操作都是读操作,写操作较少。针对这种情况,可以使用 JDK1.5 提供的读写锁(java.util.concurrent.locks.ReadWriteLock)。代码如下 

     

    rwlock.readLock().lock();
    value = map.get(key);
    rwlock.readLock().unlock();
     

     

  4. 使用 JDK1.5 提供的 java.util.concurrent.ConcurrentHashMap 类。该类将 Map 的存储空间分为若干块,每块拥有自己的锁,大大减少了多个线程争夺同一个锁的情况。代码如下 

     

    value = map.get(key); //同步机制内置在 get 方法中
     

     

  5. 结论: 

    写了段测试代码,针对这四种方式进行测试,结果见附图。测试内容为 1 秒钟所有 get 方法调用次数的总和。为了比较,增加了未使用任何同步机制的情况(非安全!)。理论上,不同步应该最快。 

    我的 CPU 是双核的(Core 2 Duo E6300),因此太多线程也没啥意义,所以只列出了单线程、两个线程和五个线程的情况。更多线程时,CPU 利用率提高,但增加了线程调度的开销,测试结果与五个线程差不多。 


    从附图可以看出: 

    1、不同步确实最快,与预期一致。 
    2、四种同步方式中,ConcurrentHashMap 是最快的,接近不同步的情况。 
    3、synchronized 关键字非常慢,比使用锁慢了两个数量级。真是大跌眼镜,我很迷惑为什会 synchronized 慢到这个程度。 
    4、使用读写锁的读锁,比普通所稍慢。这个比较意外,可能硬件或测试代码没有发挥出读锁的全部功效。

     



    因此总结如下:

    1、如果 ConcurrentHashMap 够用,则使用 ConcurrentHashMap。 
    2、如果需自己实现同步,则使用 JDK1.5 提供的锁机制,避免使用 synchronized 关键字。 

     


     

    上图为原作者的数据,下图是我的机器实测数据:

    CPU:Core 2 Duo T6570 双核 内存2G

    之所以增加了一个16线程,是因为ConcurrentHashMap使用了16个分离锁。。好象是。。。

     

    一个线程

    两个线程

    五个线程

    16个线程

    方法1(使用synchronized关键字

    7,542,649

    3,920,280

    3,731,002

    4,178,659

    方法2(使用Lock

    7,737,160

    4,532,817

    5,392,027

    5,591,125

    方法3(使用ReadLock

    5,935,673

    6,109,870

    5,996,307

    8633877(6013883)

    方法4(使用ConcurrentHashMap

    10,108,220

    19,989,279

    23,787,126

    23,384,236

    方法0(不使用任何同步机制,非安全)

    13,393,506

    24,813,267

    28,846,768

    31,234,310

     (注:上图红色部分为最小值,读写分离锁波动比较大,所以记录了最小值)

    注:内部锁在jdk6上已经有比较大的改进,而原作者使用的是JDK1.5版本因此上表的数据可能和原作者的数据有少许偏差,有兴趣可以测试不同JDK版本之间的差异)

     

 

测试代码

 

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;

public class MapTest
{
	public static final int THREAD_COUNT = 1;
	public static final int MAP_SIZE = 1000;
	public static final int EXECUTION_MILLES = 1000;
	public static final int[] KEYS = new int[100]; 
	
	public static void main(String[] args) throws Exception
	{
		//初始化
		Random rand = new Random();
		for (int i = 0; i < KEYS.length; ++i)
		{
			KEYS[i] = rand.nextInt();
		}
				
		//创建线程
		long start = System.currentTimeMillis();
		Thread[] threads = new Thread[THREAD_COUNT];
		for (int i = 0; i < THREAD_COUNT; ++i)
		{
			//threads[i] = new UnsafeThread();
			//threads[i] = new SynchronizedThread();
			//threads[i] = new LockThread();
			//threads[i] = new ReadLockThread();
			threads[i] = new ConcurrentThread();
			threads[i].start();
		}
		
		//等待其它线程执行若干时间
		Thread.sleep(EXECUTION_MILLES);

		//统计 get 操作的次数
		long sum = 0;		
		for (int i = 0; i < THREAD_COUNT; ++i)
		{
			sum += threads[i].getClass().getDeclaredField("count").getLong(threads[i]);
		}
		long millisCost = System.currentTimeMillis() - start;
		System.out.println(sum + "(" + (millisCost) + "ms)");
		System.exit(0);
	}
	
	public static void fillMap(Map<Integer, Integer> map)
	{
		Random rand = new Random();
		
		for (int i = 0; i < MAP_SIZE; ++i)
		{
			map.put(rand.nextInt(), rand.nextInt());
		}
	}
}

class UnsafeThread extends Thread
{
	private static Map<Integer, Integer> map = new HashMap<Integer, Integer>();	
	public long count = 0;	
	
	static
	{
		MapTest.fillMap(map);
	}
	
	public void run()
	{
		for (;;)
		{
			int index = (int)(count % MapTest.KEYS.length);
			map.get(MapTest.KEYS[index]);
			++count;
		}
	}
}

class SynchronizedThread extends Thread
{
	private static Map<Integer, Integer> map = new HashMap<Integer, Integer>();	
	public long count = 0;
	
	static
	{
		MapTest.fillMap(map);
	}
	
	public void run()
	{
		for (;;)
		{
			int index = (int)(count % MapTest.KEYS.length);
			synchronized(SynchronizedThread.class)
			{
				map.get(MapTest.KEYS[index]);
			}
			++count;
		}
	}
}

class LockThread extends Thread
{
	private static Map<Integer, Integer> map = new HashMap<Integer, Integer>();	
	private static Lock lock = new ReentrantLock();
	public long count = 0;
	
	static
	{
		MapTest.fillMap(map);
	}
	
	public void run()
	{
		for (;;)
		{
			int index = (int)(count % MapTest.KEYS.length);
			lock.lock();
			map.get(MapTest.KEYS[index]);
			lock.unlock();
			++count;
		}
	}
}

class ReadLockThread extends Thread
{
	private static Map<Integer, Integer> map = new HashMap<Integer, Integer>();	
	private static Lock lock = new ReentrantReadWriteLock().readLock();
	public long count = 0;
	
	static
	{
		MapTest.fillMap(map);
	}
	
	public void run()
	{
		for (;;)
		{
			int index = (int)(count % MapTest.KEYS.length);
			lock.lock();
			map.get(MapTest.KEYS[index]);
			lock.unlock();
			++count;
		}
	}
}

class ConcurrentThread extends Thread
{
	private static Map<Integer, Integer> map = new ConcurrentHashMap<Integer, Integer>();	
	public long count = 0;
	
	static
	{
		MapTest.fillMap(map);
	}
	
	public void run()
	{
		for (;;)
		{
			int index = (int)(count % MapTest.KEYS.length);
			map.get(MapTest.KEYS[index]);
			++count;
		}
	}
}
 

 

 

 

 

 

 

 

2011-02-24 david.wang

分享到:
评论

相关推荐

    Java中的`java.util.stream.Collectors.toMap()`方法有什么作用

    在Java中,java.util.stream.Collectors.toMap()方法是一个非常实用的工具,它允许我们将流(Stream)中的元素收集到一个Map中。这个方法是Collectors类中的一个静态方法,它实现了Collector接口,用于在流的终止...

    Java常用Util类

    14. **Stream**: Java 8的新特性,提供了一种新的数据处理方式,可以对集合进行函数式编程。 在你提供的压缩包`ZycUtil`中,可能包含了上述或其他自定义的Util类,这些类可能是对Java标准库Util类的扩展或补充,...

    java util工具类3

    java util工具类2java util工具类2java util工具类2java util工具类2

    Java常用工具类UtilClass

    在Java编程中,工具类(Util Class)是包含各种实用函数的静态类,它们提供了一种简化常见任务的方法。在给定的`UtilClass`中,我们有五个主要的工具类:`StringUtil`、`FileUtil`、`ConnectDB`、`DateUtil`和`...

    java常用util工具类

    Java中的`util`工具类是Java Standard Edition (Java SE)库中的重要组成部分,它们提供了许多实用功能,极大地简化了开发工作。在这个主题中,我们将深入探讨`StringUtil`、`FileUtil`、`MD5`、`JsonUtil`以及`...

    java常用util类

    在Java编程语言中,`util`包是Java标准库中的一个核心部分,包含了大量实用工具类,极大地丰富了开发者的代码库。这个包下有很多重要的类,如ArrayList、HashMap、LinkedList、Date、Calendar等,它们提供了许多常用...

    java util工具类1

    13. **Stream API**:自Java 8起,`java.util.stream`包提供了Stream API,它允许以声明性方式处理数据,适用于大量数据的处理和并行计算。 14. **EnumSet和EnumMap**:专门为枚举类型设计的集合,提供了高效的存储...

    java中jython操作把python数据类型转成java类型

    在Java中,Jython是一个非常有用的工具,它允许我们在Java应用程序中嵌入Python代码,并能够无缝地在Python数据类型和Java数据类型之间进行转换。这极大地扩展了Java的生态系统,让我们能够利用Python丰富的库和简洁...

    java Pojo转Map

    在Java编程中,Pojo(Plain Old Java Object)是一种简单的对象模型,通常用于表示数据实体。Map接口则是Java集合框架的一部分,它提供了键值对的数据存储方式,方便数据的存取。将Pojo对象转换为Map,可以简化数据...

    java.util包

    Java.util包是Java标准库中的核心包之一,它包含了大量用于通用编程的类和接口,是Java开发中不可或缺的一部分。这个包提供了数据结构、集合框架、事件处理、日期时间、随机数生成、位集以及与I/O流操作相关的辅助...

    Mysql、orcale 中的数据类型与java中的数据类型对应表.pdf

    Mysql、Oracle 中的数据类型与 Java 中的数据类型对应表 MySQL 和 Oracle 是两种常用的关系型数据库管理系统,而 Java 是一种广泛应用于企业级应用开发的编程语言。在数据库应用开发中,理解数据类型的对应关系...

    无法解析类型 java.util.Map$Entry。从必需的 .class 文件间接引用了它

    这是我在编写struts2中遇到的问题,整理出来,包括截图,希望可以帮到大家

    java常用的util工具类

    Java的`util`工具类是Java Standard Library中的核心部分,包含了大量的实用类和接口,极大地提高了开发效率。这里我们将深入探讨几个在标题和描述中提到的`util`工具类及其在实际项目中的应用。 1. **MD5加密**: `...

    java Util

    Java Util是Java编程语言中的一个核心包,包含了各种实用工具类,这些类提供了大量的静态方法,用于处理数组、集合、日期时间、字符流等常见任务。这个包的重要性在于它为开发者提供了一组基础且强大的工具,极大地...

    Java常用的强转类型,基本数据类型转换,JSONObject强转Map,JSONArray强转List(附源码)

    本文将深入探讨Java中的一些关键转换技术,包括基本数据类型的转换、JSONObject到Map的转换以及JSONArray到List的转换,并提供相关的源码示例。 一、基本数据类型转换 1. 自动类型转换:当我们将一个范围小的数据...

    java工具类 java开发助手 java util

    Java工具类(Java Util)是Java开发中不可或缺的一部分,它为开发者提供了大量便捷的功能,极大地提高了开发效率。在Java标准库中,`java.util`包是核心工具类库,包含了各种容器类、集合框架、日期时间处理、随机数...

    用java.util.zip包现数据压缩与解压

    ### 使用 Java.util.zip 包实现数据压缩与解压 在计算机科学领域,数据压缩技术是一项重要的功能,它能够帮助减少存储空间的需求以及提高网络传输效率。本文将通过一系列的示例来详细介绍如何利用 Java 中的 `java....

    Java常用Util类Jar

    在Java中,`java.util` 包是最基础也是最常用的工具类集合,而"Java常用Util类Jar"则是一个包含了更多自定义或者网络上流行实用工具类的集合,适用于Web项目的快速开发。 这个压缩包中的`ZycUtil`可能是一个自定义...

    java中将数据库中数据赋值给Map对象源代码

    在Java开发中,特别是在使用Spring框架时,将数据库中的数据转换为Map对象是一种常见的操作。这样做可以简化数据处理,使得数据以键值对的形式存储,便于快速查找和使用。Spring框架提供了强大的数据访问抽象,包括...

    The java.util.concurrent Synchronizer Framework

    同步器是一种抽象数据类型(Abstract Data Type, ADT),它维护了一个内部同步状态(例如表示一个锁是否被锁定),提供了更新和检查该状态的方法,以及至少一个方法,当满足某些条件时会使调用线程阻塞,直到其他...

Global site tag (gtag.js) - Google Analytics