"原子操作(atomic operation)是不需要synchronized",这是Java多线程编程的老生常谈了。所谓原子操作是指不会被线程调度机制打断的操作;这种操 作一旦开始,就一直运行倒结束,中间不会有任何 context switch (切换到另一个线程)。 通常所说的原子操作包括对非long和double型的primitive进行赋值,以及返回这两者之外的primitive。之所以要把它们排除在外是 因为它们都比较大,而JVM的设计规范又没有要求读操作和赋值操作必须是原子操作(JVM可以试着去这么作,但并不保证)。不过如果你在long或 double前面加了volatile,那么它就肯定是原子操作了。
oncurrentHashMap:
支持检索的完全并发和更新的所期望可调整并发的哈希表。此类遵守与 Hashtable 相同的功能规范,并且包括对应于 Hashtable 的每个方法的方法版本。不过,尽管所有操作都是线程安全的,但检索操作不 必锁定,并且不 支持以某种
防止所有访问的方式锁定整个表。此类可以通过程序完全与 Hashtable 进行互操作,这取决于其线程安全,而与其同
步细节无关。
CopyOnWriteArrayList:
ArrayList 的一个线程安全的变体,其中所有可变操作(添加、设置,等等)都是通过对基础数组进行一次新的复制来
实现的。这一般需要很大的开销,但是当遍历操作的数量大大超过可变操作的数量时,这种方法可能比其他替代方法更
有效。在不能或不想进行同步遍历,但又需要从并发线程中排除冲突时,它也很有用。
ConcurrentHashMap<String,String> map; String getString(String name) { String x = map.get(name); if (x == null) { x = new String(); map.put(name, x); } return x; }
如果你只调用get(),或只调用put()时,ConcurrentHashMap是线程安全的。
但是,在你调用完get后,调用put之前,
如果有另外一个线程调用了map.put(name, x),
你再去执行map.put(name,x),
就很可能把前面的操作结果覆盖掉了。
所以,即使在线程安全的情况下,
你还是有可能违反原子操作的规则
ConcurrentHashMap有putIfAbsent(),CopyOnWriteArrayList有addIfAbsent(),使你能方便的实现检查然后操作的原子化。
ConcurrentHashMap<String, CopyOnWriteArrayList<Integer>> map; CopyOnWriteArrayList<Integer> getList(String name) { CopyOnWriteArrayList<Integer> x = map.get(name); if (x == null) { x = new CopyOnWriteArrayList<Integer>(); map.putIfAbsent(name, x); // map.put(name, x); } return x; } /**增加时加锁 * @param name * @param id */ void addID(String name,Integer id){ CopyOnWriteArrayList<Integer> x = map.get(name); if (x == null) { x = new CopyOnWriteArrayList<Integer>(); x.addIfAbsent(id); map.putIfAbsent(name, x); // map.put(name, x); } }