现在的位置: 首页Java技术 > 正文
Java Map线程安全的4种实现方法及代码
关键词:Java Map ┊ 来源: 原创收藏

如果需要使 Map 线程安全,大致有这么四种方法: 
1、使用 synchronized 关键字,代码如下 
Java代码
  1. synchronized(anObject) {     
  2.     value = map.get(key);  
  3. }  
  

2、使用 JDK1.5提供的锁(java.util.concurrent.locks.Lock)。代码如下 
Java代码
  1. lock.lock();     
  2. value = map.get(key);     
  3. lock.unlock();  
  

3、使用 JDK1.5 提供的读写锁(java.util.concurrent.locks.ReadWriteLock)。代码如下 
Java代码 
  1. rwlock.readLock().lock();     
  2. value = map.get(key);     
  3. rwlock.readLock().unlock();  
  
这样两个读操作可以同时进行,理论上效率会比方法 2 高。 

4、使用 JDK1.5 提供的 java.util.concurrent.ConcurrentHashMap 类。该类将 Map 的存储空间分为若干块,每块拥有自己的锁,大大减少了多个线程争夺同一个锁的情况。代码如下 
value = map.get(key); //同步机制内置在 get 方法中 

比较: 

1、不同步确实最快,与预期一致。 
2、四种同步方式中,ConcurrentHashMap 是最快的,接近不同步的情况。 
3、synchronized 关键字非常慢,比使用锁慢了两个数量级。如果需自己实现同步,则使用 JDK1.5 提供的锁机制,避免使用 synchronized 关键字。 

Java代码
  1. public class MapTest{     
  2.     public static final int THREAD_COUNT = 1;     
  3.     public static final int MAP_SIZE = 1000;     
  4.     public static final int EXECUTION_MILLES = 1000;     
  5.     public static final int[] KEYS = new int[100];            
  6.     public static void main(String[] args) throws Exception{     
  7.   
  8.         //初始化     
  9.         Random rand = new Random();     
  10.         for (int i = 0; i < KEYS.length; ++i)  KEYS[i] = rand.nextInt();     
  11.      //创建线程     
  12.       long start = System.currentTimeMillis();     
  13.       Thread[] threads = new Thread[THREAD_COUNT];     
  14.       for (int i = 0; i < THREAD_COUNT; ++i) {     
  15.           threads[i] = new SynchronizedThread();     
  16.           //threads[i] = new LockThread();     
  17.            threads[i].start();     
  18.       }     
  19.   
  20.        //等待其它线程执行若干时间     
  21.         Thread.sleep(EXECUTION_MILLES);  
  22.         //统计 get 操作的次数     
  23.         long sum = 0;            
  24.         for (int i = 0; i < THREAD_COUNT; ++i){     
  25.         sum += threads[i].getClass().getDeclaredField("count").getLong(threads[i]);           }     
  26.         long millisCost = System.currentTimeMillis() - start;     
  27.         System.out.println(sum + "(" + (millisCost) + "ms)");     
  28.         System.exit(0);     
  29.     }     
  30.          
  31.     public static void fillMap(Map<Integer, Integer> map){     
  32.         Random rand = new Random();  
  33.         for (int i = 0; i < MAP_SIZE; ++i){     
  34.             map.put(rand.nextInt(), rand.nextInt());     
  35.         }     
  36.     }     
  37. }     
  38. class SynchronizedThread extends Thread{     
  39.     private static Map<Integer, Integer> map = new HashMap<Integer, Integer>();      
  40.     public long count = 0;  
  41.     static {     
  42.         MapTest.fillMap(map);     
  43.     }     
  44.     public void run()  {     
  45.         for (;;) {     
  46.             int index = (int)(count % MapTest.KEYS.length);     
  47.             synchronized(SynchronizedThread.class){     
  48.                 map.get(MapTest.KEYS[index]);     
  49.             }     
  50.             ++count;     
  51.         }     
  52.     }     
  53. }     
  54.   
  55.   
  56.   
  57. class LockThread extends Thread{     
  58.     private static Map<Integer, Integer> map = new HashMap<Integer, Integer>();      
  59.     private static Lock lock = new ReentrantLock();     
  60.     public long count = 0;           
  61.     static {     
  62.         MapTest.fillMap(map);     
  63.     }            
  64.     public void run() {     
  65.         for (;;) {     
  66.             int index = (int)(count % MapTest.KEYS.length);     
  67.             lock.lock();     
  68.             map.get(MapTest.KEYS[index]);     
  69.             lock.unlock();     
  70.             ++count;     
  71.         }     
  72.     }     
  73. }  



以下两种写法的区别: 
Java代码 
  1. synchronized(anObject)    
  2. {    
  3.     value = map.get(key);    
  4. }  
  5. synchronized(anObject)    
  6. {    
  7.     map.put(key, value);    
  8. }  

这样因该是线程安全的,只要保证put和get都同步到这个anObject上来 

Java代码
  1. synchronized(key)    
  2. {    
  3.     value = map.get(key);    
  4. }   
  5. synchronized(key)    
  6. {    
  7.     map.put(key, value);   
  8. }  

这种写法可能会有问题,因为get和put的key可能是不同的对象
本文由 jack 发布于 3010天 3小时 49分钟前,目前已有 15118 人浏览
欢迎大家转载分享,请注明来源及链接;商业媒体转载请获得授权,谢谢合作!
 

添加评论