Concurrency: Performance Tuning

1. Comparing Mutex Technologies

  Lock的效率通常比synchronized高,但使用synchronized具有更好的可读性。如果加锁的代码比较耗时,耗费在加锁和解锁上的时间就会显得微不足道。

2. Lock-Free Containers

  Java SE5加入了新的线程安全的容器类,不使用互斥锁,提高了性能。其基本策略是,对容器的修改和读取可以同时进行:对容器的修改会先在单独的副本上完成,修改完成后,被修改的副本会替换掉原容器中的对应内容;从容器中进行读取时,只能读取到已经完成的修改。

  CopyOnWriteArrayList会在被修改时创建整个数组的副本,原数组还会被保留,提供安全的读取。修改完成后,原数组会被替换为修改后的数组(这个替换是一个原子操作),之后的读取就可以获得修改后的数据。CopyOnWriteArrayList不会在多个迭代器遍历和修改列表时抛出ConcurrentModificationException

  CopyOnWriteArraySet使用CopyOnWriteArrayList实现Lock-Free。

  ConcurrentHashMapConcurrentLinkedQueue也使用类似的方式来允许同时读写,但在写入时只会有部分内容被复制。

3. Optimistic Locking

  部分Atomic类允许乐观锁定(Optimistic Locking),在进行计算时不使用互斥锁,计算完成后,再通过compareAndSet()更新Atomic类。compareAndSet()需要同时提供一个旧值和一个新值,如果旧值和当前Atomic对象的值不同(其他任务也同时进行了修改),compareAndSet()会失败。通常我们使用互斥锁来防止多个任务同时修改同一个对象;但有时候我们会乐观的认为要修改的对象不会同时被其他任务修改,不使用锁定,从而获得性能上的提升。

4. ReadWriteLocks

  ReadWriteLock可以在没有写入的时候允许多个任务同时读取共享资源。当有任务进行写入时,写锁定被打开,此时所有任务都无法读取,直到写锁定释放。

  对于写入较少而有多个任务读取的场景,ReadWriteLock会产生一定的优化效果。

  一个例子如下: