性能主题

Java性能优化要点之五: 队列与lazySet

首页

  队列需要对正确的应用使用好正确的队列Queue,否则会产生性能问题,队列分生产者和消费者,或者发布者订阅者,它们之间有一对多和多对多以及多对一等关系。

SPSC:一个Producer :一个Consumer
SPMC:一个Producer :多个Consumer
MPSC:多个Producer :多个Consumer
MPMC:多个Producer :多个Consumer

记住:在JDK中所有并发的队列Queue都是MPMC。JAQ-InABox是一个提高了性能的Queue实现。

 

Atomic*.lazySet(…)

根据单写原理,JDK的AtomicLong.lazySet等方法是便宜的最好性能,成本低便宜的volatile 写总是受大家欢迎,前提是只有一个写入者,也就是一个Producer。

以AtomicReference的lazySet为例子,其代码如下:

public final void lazySet(V newValue) {

 

           unsafe.putOrderedObject(this, valueOffset, newValue);

 

}

lazySet是使用Unsafe.putOrderedObject方法,这个方法在对低延迟代码是很有用的,它能够实现非堵塞的写入,这些写入不会被Java的JIT重新排序指令(instruction reordering),这样它使用快速的存储-存储(store-store) barrier, 而不是较慢的存储-加载(store-load) barrier, 后者总是用在volatile的写操作上,这种性能提升是有代价的,虽然便宜,也就是写后结果并不会被其他线程看到,甚至是自己的线程,通常是几纳秒后被其他线程看到,这个时间比较短,所以代价可以忍受。

类似Unsafe.putOrderedObject还有unsafe.putOrderedLong等方法,unsafe.putOrderedLong比使用 volatile long要快3倍左右。.

在DDD中有值对象概念,值对象的特点是不可变的,而我们经常要修改的状态是可变的,结合lazySet和值对象我们可以编写并发性很好的可变状态修改。

比如:Forum论坛有一个论坛状态ForumState,论坛状态主要是当前最新的帖子等信息,每次有新贴发布时,会更新论坛状态,我们将ForumState设计成一个值对象,一旦有新的帖子发布,就创建一个新的对象 ForumState,然后替换掉旧的状态,这种替换动作可以使用AtomicLong.lazySet来完成。

public class Forum extends ForumModel {

  private volatile AtomicReference<ForumState> forumState;

  public ForumState getForumState() {
   try {
    return forumState.get();
   } finally {
   }
  }

  public void setForumState(ForumState forumState) {
   this.forumState.lazySet(forumState);
  }

..

}

下页