金色坐标

关注互联网应用和搜索引擎技术

« JDK5引入的线程并发开发concurrent包(一)JDK5引入的线程并发开发concurrent包(三) »

JDK5引入的线程并发开发concurrent包(二)

Java 5中引入了并发包(java.util.concurrent),大大简化了多线程并发程序的开发。接下来我们分析一下引入concurrent包为多线程并发程序带来的变化。为清晰期间,进行对比说明。

第二,集合(Collections)的线程安全

1,Synchronized  Collections

Vector和Hashtable是采用Synchronized的方案的线程安全的集合类。对应的线程不安全的类型为:ArrayList和HashMap。

另外,Java 1.2 引入了对集合线程安全便利封装的函数:Collections.synchronizedXxx (比如Collections.synchronizedList)。

示例如下:

List<String> mySafeList = Collections.synchronizedList(new ArrayList<String>());
Map<String, Object> mySafeMap = Collections.synchronizedMap(new HashMap<String, Object>());

这样被封装过的集合在被访问的各个方法均为等价于加了Synchronized修饰符的。

2,Concurrent Collections

Synchronized  Collections性能比较低,而ArrayList和HashMap这类又在多线程访问的时候不安全,Java 5引入了基于copywirte、Lock Striping和compare and set等技术的Concurrent Collections。

类型 非线程安全版 采用技术 备注
ConcurrentHashMap HashMap Lock Striping & compare and set 将key分组,每组使用不同的同步锁
ConcurrentSkipListMap(Java 6) SortedMap 如上 如上
CopyOnWriteArrayList ArrayList copy on wirte 发生修改时候做copy,新老版本分离,保证读的高性能,适用于以读为主的情况
ConcurrentSkipListSet(Java 6) SortedSet 如上 如上


下面代码简单示例了采用Lock Striping技术实现一个线程安全的高效的Map。

@ThreadSafe
public class StripedMap {
    // Synchronization policy: buckets[n] guarded by locks[n%N_LOCKS]
    private static final int N_LOCKS = 16;
    private final Node[] buckets;
    private final Object[] locks;

    private static class Node { ... }

    public StripedMap(int numBuckets) {
        buckets = new Node[numBuckets];
        locks = new Object[N_LOCKS];
        for (int i = 0; i < N_LOCKS; i++)
            locks[i] = new Object();
    }

    private final int hash(Object key) {
        return Math.abs(key.hashCode() % buckets.length);
    }

    public Object get(Object key) {
        int hash = hash(key);
        synchronized (locks[hash % N_LOCKS]) {
            for (Node m = buckets[hash]; m != null; m = m.next)
                if (m.key.equals(key))
                    return m.value;
        }
        return null;
    }

    public void clear() {
        for (int i = 0; i < buckets.length; i++) {
            synchronized (locks[i % N_LOCKS]) {
                buckets[i] = null;
            }
        }
    }
    ...
}


下面是各类Map在cpu个数增加情况下的性能增长对比图:

可以看到Synchronized  Collections在cpu个数增加到2个时,性能严重下滑,以后没有什么变化。而新的Concurrent Collections保持接近lg(n)的增长。


第三,原子变量(Atomic Variable)

解决“cpu cache导致的线程安全问题”的另外一个简单的方式就是使用Java 5提供的原子变量:AtomicInteger, AtomicLong, AtomicBoolean, 和 AtomicReference。

浮点数可以使用 Float.floatToIntBits或者 Double.doubleToLongBits的方法进行转换。和volatile相比还提供了compareAndSet的方法,以便支持基于此的实现复杂高效的并发处理。

未完待续...




原创文章,如转载请注明:转载自金色坐标 [ http://www.kingxy.com/ ]

本文链接地址:http://www.kingxy.com/archives/203.html
  • quote 7.高于怡
  • http://www.bkl888.com

  • List<String> mySafeList = Collections.synchronizedList(new ArrayList<String>());
    Map<String, Object> mySafeMap = Collections.synchronizedMap(new HashMap<String, Object>());
    本文来源于金色坐标 http://www.kingxy.com/ , 原文地址:http://www.kingxy.com/archives/203.html


    joy 于 2010-2-2 13:04:11 回复
    ??
  • 2010-2-1 14:50:45 回复该留言

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

订阅博客

  • 订阅我的博客:订阅我的博客
  • 通过Google订阅本站
  • 通过bloglines订阅本站
  • 通过抓虾订阅本站
  • 通过yahoo订阅本站

Search

Google

最新评论及回复

最近发表

金色坐标博客——京ICP备09009094号

本站采用创作共用版权协议, 要求署名、非商业用途和保持一致. 转载本站内容必须也遵循“署名-非商业用途-保持一致”的创作共用协议.
KingXY Blog - This site is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License.