`

Map 四种同步方式的性能比较

阅读更多

如果需要使 Map 线程安全,大致有这么四种方法:

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

Java代码 复制代码
  1. synchronized(anObject)   
  2. {   
  3.     value = map.get(key);   
  4. }  
synchronized(anObject)
{
	value = map.get(key);
}



JDK1.2 提供了 Collections.synchronizedMap(originMap) 方法,同步方式其实和上面这段代码相同。

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

Java代码 复制代码
  1. lock.lock();   
  2. value = map.get(key);   
  3. lock.unlock();  
lock.lock();
value = map.get(key);
lock.unlock();



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

Java代码 复制代码
  1. rwlock.readLock().lock();   
  2. value = map.get(key);   
  3. rwlock.readLock().unlock();  
rwlock.readLock().lock();
value = map.get(key);
rwlock.readLock().unlock();



这样两个读操作可以同时进行,理论上效率会比方法 2 高。

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

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




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

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

从附图可以看出:

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

结论:

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



 

  • 描述: 多个线程每秒 Map.get 的执行次数之和
  • 大小: 28.8 KB
  • 测试代码。只图方便了,不大 OO,见笑。


    Java代码 复制代码
    1. import java.util.*;   
    2. import java.util.concurrent.*;   
    3. import java.util.concurrent.locks.*;   
    4.   
    5. public class MapTest   
    6. {   
    7.     public static final int THREAD_COUNT = 1;   
    8.     public static final int MAP_SIZE = 1000;   
    9.     public static final int EXECUTION_MILLES = 1000;   
    10.     public static final int[] KEYS = new int[100];    
    11.        
    12.     public static void main(String[] args) throws Exception   
    13.     {   
    14.         //初始化   
    15.         Random rand = new Random();   
    16.         for (int i = 0; i < KEYS.length; ++i)   
    17.         {   
    18.             KEYS[i] = rand.nextInt();   
    19.         }   
    20.                    
    21.         //创建线程   
    22.         long start = System.currentTimeMillis();   
    23.         Thread[] threads = new Thread[THREAD_COUNT];   
    24.         for (int i = 0; i < THREAD_COUNT; ++i)   
    25.         {   
    26.             //threads[i] = new UnsafeThread();   
    27.             //threads[i] = new SynchronizedThread();   
    28.             //threads[i] = new LockThread();   
    29.             //threads[i] = new ReadLockThread();   
    30.             threads[i] = new ConcurrentThread();   
    31.             threads[i].start();   
    32.         }   
    33.            
    34.         //等待其它线程执行若干时间   
    35.         Thread.sleep(EXECUTION_MILLES);   
    36.   
    37.         //统计 get 操作的次数   
    38.         long sum = 0;          
    39.         for (int i = 0; i < THREAD_COUNT; ++i)   
    40.         {   
    41.             sum += threads[i].getClass().getDeclaredField("count").getLong(threads[i]);   
    42.         }   
    43.         long millisCost = System.currentTimeMillis() - start;   
    44.         System.out.println(sum + "(" + (millisCost) + "ms)");   
    45.         System.exit(0);   
    46.     }   
    47.        
    48.     public static void fillMap(Map<Integer, Integer> map)   
    49.     {   
    50.         Random rand = new Random();   
    51.            
    52.         for (int i = 0; i < MAP_SIZE; ++i)   
    53.         {   
    54.             map.put(rand.nextInt(), rand.nextInt());   
    55.         }   
    56.     }   
    57. }   
    58.   
    59. class UnsafeThread extends Thread   
    60. {   
    61.     private static Map<Integer, Integer> map = new HashMap<Integer, Integer>();    
    62.     public long count = 0;     
    63.        
    64.     static  
    65.     {   
    66.         MapTest.fillMap(map);   
    67.     }   
    68.        
    69.     public void run()   
    70.     {   
    71.         for (;;)   
    72.         {   
    73.             int index = (int)(count % MapTest.KEYS.length);   
    74.             map.get(MapTest.KEYS[index]);   
    75.             ++count;   
    76.         }   
    77.     }   
    78. }   
    79.   
    80. class SynchronizedThread extends Thread   
    81. {   
    82.     private static Map<Integer, Integer> map = new HashMap<Integer, Integer>();    
    83.     public long count = 0;   
    84.        
    85.     static  
    86.     {   
    87.         MapTest.fillMap(map);   
    88.     }   
    89.        
    90.     public void run()   
    91.     {   
    92.         for (;;)   
    93.         {   
    94.             int index = (int)(count % MapTest.KEYS.length);   
    95.             synchronized(SynchronizedThread.class)   
    96.             {   
    97.                 map.get(MapTest.KEYS[index]);   
    98.             }   
    99.             ++count;   
    100.         }   
    101.     }   
    102. }   
    103.   
    104. class LockThread extends Thread   
    105. {   
    106.     private static Map<Integer, Integer> map = new HashMap<Integer, Integer>();    
    107.     private static Lock lock = new ReentrantLock();   
    108.     public long count = 0;   
    109.        
    110.     static  
    111.     {   
    112.         MapTest.fillMap(map);   
    113.     }   
    114.        
    115.     public void run()   
    116.     {   
    117.         for (;;)   
    118.         {   
    119.             int index = (int)(count % MapTest.KEYS.length);   
    120.             lock.lock();   
    121.             map.get(MapTest.KEYS[index]);   
    122.             lock.unlock();   
    123.             ++count;   
    124.         }   
    125.     }   
    126. }   
    127.   
    128. class ReadLockThread extends Thread   
    129. {   
    130.     private static Map<Integer, Integer> map = new HashMap<Integer, Integer>();    
    131.     private static Lock lock = new ReentrantReadWriteLock().readLock();   
    132.     public long count = 0;   
    133.        
    134.     static  
    135.     {   
    136.         MapTest.fillMap(map);   
    137.     }   
    138.        
    139.     public void run()   
    140.     {   
    141.         for (;;)   
    142.         {   
    143.             int index = (int)(count % MapTest.KEYS.length);   
    144.             lock.lock();   
    145.             map.get(MapTest.KEYS[index]);   
    146.             lock.unlock();   
    147.             ++count;   
    148.         }   
    149.     }   
    150. }   
    151.   
    152. class ConcurrentThread extends Thread   
    153. {   
    154.     private static Map<Integer, Integer> map = new ConcurrentHashMap<Integer, Integer>();      
    155.     public long count = 0;   
    156.        
    157.     static  
    158.     {   
    159.         MapTest.fillMap(map);   
    160.     }   
    161.        
    162.     public void run()   
    163.     {   
    164.         for (;;)   
    165.         {   
    166.             int index = (int)(count % MapTest.KEYS.length);   
    167.             map.get(MapTest.KEYS[index]);   
    168.             ++count;   
    169.         }   
    170.     }   
    171. }  
    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;
    		}
    	}
    }
    • 大小: 28.8 KB
    分享到:
    评论
    1 楼 nishizhutou 2009-12-06  
    谢谢,那我就直接用ConcurrentHashMap了.
    另外,对于map,什么情况下需要同步?如果我确认不同线程使用的是Map里不同的对象,应该不用同步吧?
    本来我是想研究这个的,现在一看ConcurrentHashMap的性能这么好,干脆用它好了,还更保险, 

    相关推荐

      基于JMAG RT v16.0的永磁同步电机效率Map 图计算.pdf

      在永磁同步电机的设计和优化过程中,电机效率Map图是一种重要的工具,它能够直观地表示电机在不同工况下的效率表现。传统的电机测试方法依赖于实际样机的测试,这不仅耗时耗力,而且成本高昂。随着计算机技术的发展...

      电机map图及结果分析.doc

      电机效率MAP图是一种重要的工具,用于描绘电机在不同转矩和转速下的工作效率。在电机设计和优化过程中,理解并分析MAP图对于提高整体系统的性能至关重要。本文档提供了绘制电机效率MAP图的MATLAB代码,并引用了两篇...

      js代码-js -- 实现同步map函数

      在JavaScript中,`Array.prototype.map()`是一个非常常用的数组方法,它创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后的...在实际开发中,应根据具体需求和场景选择合适的同步或异步处理方式。

      Java Map 集合类简介

      然而,Map提供了一种更为通用的数据存储方式。它不按照数值索引存储元素,而是通过键(Key)来映射对应的值(Value)。从概念上讲,可以将List视为键为数值的特殊Map,但实际上两者之间没有直接的关系。Map在Java中...

      electric_car_电动汽车、性能测试、电池_电机MAP图_电机MAP_电池_电动汽车.zip

      在这个压缩包文件"electric_car_电动汽车、性能测试、电池_电机MAP图_电机MAP_电池_电动汽车.zip"中,我们可以期待找到与电动汽车性能测试、电池特性和电机性能相关的源代码。 源码通常是程序员用于开发和调试软件...

      java map 实现缓存技术

      总的来说,Java Map提供了一种简单而有效的方式实现缓存技术。开发者可以根据具体需求选择合适的Map实现,并结合各种策略来管理和维护缓存,以提升系统的响应速度和效率。在实际应用中,还可以考虑使用第三方库如...

      MAP译码算法的研究

      1. **串行级联结构**:MAP译码器通常采用串行级联的方式进行工作,这意味着多个编码器串联在一起,每个编码器对输入数据进行独立编码,然后将这些编码后的结果交织在一起进行传输。 2. **硬件实现**:MAP译码器...

      delphi7的map控件

      总的来说,Delphi 7的Map控件,通过TDictionary类,为开发人员提供了一种强大且灵活的方式来管理和操作键值对数据,广泛应用于各种数据存储和检索场景。了解并熟练掌握其使用方法,对于提升Delphi程序的效率和质量至...

      4.5kW48槽8极永磁同步电机电磁性能及其热分析 文件包含各种性能波形,磁密云图,温度曲线,效率Map图,谐波分析等

      标题中的“4.5kW48槽8极永磁同步电机电磁性能及其热分析”指的是一项关于特定电机设计的详细研究。这种电机是一种高效能的电动机,其主要特点是功率为4.5千瓦,拥有48个槽位和8个磁极。在电机设计中,槽的数量和磁极...

      电动汽车用永磁同步电机铁心采用非晶合金与硅钢的性能比较.pdf

      电动汽车用永磁同步电机铁心采用非晶合金与硅钢的性能比较 电动汽车用驱动电机的设计和制造工艺日趋成熟,从设计方面考虑电机性能的提升很难再有所突破。非晶合金是一种新型功能材料,具有高导磁率、低损耗及低...

      加锁方法对于Map

      在Java编程中,Map接口是数据结构中...具体选择哪种方式,取决于我们的需求,如并发性能、锁的粒度以及代码的可读性和维护性。同时,了解并熟练使用并发集合,如ConcurrentHashMap,能够帮助我们更高效地处理并发问题。

      Go-syncmap一个基于代码生成的Gosync.Map类型实现

      在Go编程语言中,`sync.Map`是一种线程安全的数据结构,它提供了高效并发环境下的键值对存储。`sync.Map`的实现是通过内部的锁机制来保证数据的同步,使得多个goroutine可以安全地读写数据。然而,有时我们可能需要...

      java map实例,排序

      本篇文章将详细探讨`HashMap`, `LinkedHashMap`, `TreeMap`, 和 `Hashtable`这四个常见的Map实现类,特别是它们如何处理排序的问题。 首先,`HashMap`是最常用的Map实现,它不保证元素的顺序,插入顺序和遍历顺序...

      Java中List、ArrayList、Vector及map、HashTable、HashMap分别的区别.

      在多线程环境下,需考虑同步性能,可以选择Vector或HashTable;对于内存效率和弱引用的需求,WeakHashMap是一个不错的选择。在实际应用中,通常推荐使用非同步的实现,如ArrayList和HashMap,因为它们的性能更高,...

      Map集合的继承关系图.pdf

      Map集合的这些实现类在不同的场景下具有不同的性能特点和用途。例如,HashMap在大多数情况下使用,因为它提供了最快的查找性能;TreeMap用于当你需要按键排序的时候;而ConcurrentHashMap则用于高度并发的环境。了解...

      List、ArrayList、Vector及map、HashTable、HashMap分别的区别

      Hashtable和HashMap的区别在于,Hashtable是一个同步的Map实现类,而HashMap是一个非同步的Map实现类。因为同步需要花费机器时间,所以Hashtable的执行效率要低于HashMap。 Collection框架是Java容器类的基础,它...

      对java中Map集合的讲解

      Map是Java集合框架中的一个重要组成部分,它提供了一种存储键值对(key-value pair)数据结构的方式。与List和Set不同,Map并没有直接继承自`Collection`接口,而是独立于`Collection`体系之外。Map的主要特点是它通过...

    Global site tag (gtag.js) - Google Analytics