`

Map线程安全几种实现方法

    博客分类:
  • Java
阅读更多
如果需要使 Map 线程安全,大致有这么四种方法:
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();
 
这样两个读操作可以同时进行,理论上效率会比方法 2 高。

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

比较:

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

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 SynchronizedThread();   
          //threads[i] = new LockThread();   
           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 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;   
        }   
    }   
}



以下两种写法的区别:
synchronized(anObject)  
{  
    value = map.get(key);  
}
synchronized(anObject)  
{  
    map.put(key, value);  
}

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

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

这种写法可能会有问题,因为get和put的key可能是不同的对象
分享到:
评论

相关推荐

    关于如何解决HashMap线程安全问题的介绍

    为了解决HashMap的线程不安全问题,我们可以采取以下几种策略: 1. 使用Collections.synchronizedMap():Java提供了一个便捷的方法,通过Collections.synchronizedMap()可以将HashMap转换为线程安全的Map。但是需要...

    JAVA单例模式的几种实现方法

    ### JAVA单例模式的几种实现方法 #### 一、饿汉式单例类 饿汉式单例类是在类初始化时就已经完成了实例化的操作。这种实现方式简单且线程安全,因为实例化过程是在编译期间完成的,不会受到多线程的影响。 **代码...

    高级程序员必会的HashMap的线程安全问题,适用于0~2年的.7z

    1. **使用线程安全的类**:Java提供了一些线程安全的Map实现,如`java.util.concurrent.ConcurrentHashMap`。ConcurrentHashMap使用分段锁技术,使得在保证线程安全的同时,提供了较好的并发性能。 2. **同步访问**...

    safe-map:安全的

    有几种方法可以解决此问题。 例如,英特尔的TBB包含多个“线程安全”容器。 不幸的是,您会发现它们对保留迭代器也不起作用-它们仅确保原子操作。 另一种选择是跳过使用迭代器,仅存储密钥。 但这意味着每次您要...

    java map 实现缓存技术

    使用Java Map实现缓存,我们需要考虑以下几个关键点: 1. **缓存初始化**:创建Map实例,可以是HashMap、ConcurrentHashMap或其他适合并发访问的实现,根据实际需求选择。 2. **缓存加载**:当请求的数据不在缓存...

    java_各个Map的区别

    (线程安全)此类遵守与 Hashtable 相同的功能规范,并且包括对应于 Hashtable 的每个方法的方法版本。不过,尽管所有操作都是线程安全的,但检索操作不 必锁定,并且不 支持以某种防止所有访问的方式锁定整个表。...

    Spring并发访问的线程安全性问题.docx

    解决办法是使用`Collections.synchronizedMap()`来同步HashMap,或者使用`ConcurrentHashMap`,这是一种专门为多线程环境设计的线程安全的Map实现。 ```java @Service("userService") Class UserService{ public ...

    Java Map 集合类简介

    而Hashtable是古老的线程安全实现,但在多线程环境中通常建议使用ConcurrentHashMap,后者提供了更好的并发性能。 在选择Map实现时,应考虑以下几个因素: 1. 是否需要线程安全性:如果在多线程环境中使用,可以...

    List set map集合容器的区别

    根据给定文件的信息,我们可以详细地探讨一下Java中几种主要的集合容器——List、Set以及Map的区别,并且深入了解它们各自的特性和应用场景。 ### 一、List #### 1. ArrayList - **特点**:`ArrayList`是基于动态...

    java各个Map的区别.doc

    EnumMap 不是线程安全的,如果需要在多线程环境中使用,应通过 Collections.synchronizedMap 方法进行同步。 3. **HashMap**: 它是基于哈希表实现的 Map,提供了所有可选的映射操作,允许 null 键和值。HashMap 并...

    Day17 Java 集合和泛型.pdf

    本知识点主要关注于Map接口的介绍和几种Map实现类的详解。 首先,Map是一个键值对集合,其中每个键映射到一个值,一个Map不能包含重复的键,每个键最多只能映射到一个值。Map接口中提供了许多方法,例如put方法用于...

    适合初学者的QT多线程操作的例子

    除了使用QThread直接编写多线程代码,QT还提供了`QtConcurrent`模块,它提供了一些高级的并发工具,如`run()`、`map()`和`filter()`等,可以方便地在后台线程执行函数,而无需直接管理线程。 此外,QT还支持线程池...

    C++ MFC 线程与窗口 SendMessage

    除了使用`ON_MESSAGE`和`SendMessage`之外,还有其他几种常用的方法可以实现跨线程的消息发送: 1. **使用`FindWindow`和`SendMessage`**:这种方法适用于知道目标窗口的类名或标题的情况。 ```cpp HWND hWnd = :...

    hashmap-thread-test:测试 Java HashMap 是否是线程安全的

    1. **Collections.synchronizedMap()**:可以使用`Collections.synchronizedMap()`静态方法将`HashMap`包装成线程安全的`SynchronizedMap`。但请注意,尽管这个方法可以确保并发修改的安全,但仍然无法避免迭代时的...

    多线程查保护多线程查保护

    9. **线程安全的数据结构**:标准库中的一些容器,如`std::vector`、`std::map`等,在多线程环境下使用时需要注意其线程安全问题。可以使用线程安全版本的容器,如`std::atomic_flag`和`std::atomic`。 在进行多...

    collection,map的区分

    - `HashSet`提供了一种非排序的、非线程安全的实现。 - `TreeSet`提供了一种基于红黑树的实现,可以自然排序或根据自定义比较器排序。 - `LinkedHashSet`保持了元素的插入顺序。 #### Map `Map`接口表示键值对...

    JAVA集合、多线程

    此外,还有wait()、notify()和notifyAll()方法用于线程间通信。 3. **线程池**:ExecutorService和ThreadPoolExecutor是Java提供的线程池工具,可以有效管理线程,避免频繁创建和销毁线程带来的开销。 4. **并发...

    java 运用映射的相关类(Map)

    在实际开发中,选择合适的Map实现类取决于具体需求,如是否需要有序、是否考虑线程安全、性能要求等。例如,如果你需要一个保持插入顺序且高效的Map,那么LinkedHashMap将是不错的选择;如果在多线程环境下,...

    7种单例模式

    在多线程环境下,我们需要确保单例实例的创建只发生一次,以上几种方式除了懒汉式(线程不安全)外,都能保证线程安全。对于反序列化测试,由于默认反序列化会生成新实例,需要重写 `readResolve()` 方法来防止这种...

    json 转为map 适合java

    * 实现数据共享:map 可以实现数据共享,多个线程或进程可以共享同一个 map 对象。 三、如何将 json 转换为 map 在 Java 中,可以使用多种方法将 json 转换为 map。下面是一个使用 JSONObject 和 ListOrderedMap ...

Global site tag (gtag.js) - Google Analytics