/*
* @author lihong
* @date 2016年1月1日 下午5:20:02
* @version v1.0
*/
package com.lihong.DDPush;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
/**
* 生产者只有一个,消费者有多个,每次消费者都会把整个老队列拿走,新建一个队列替换老的队列,
* 以便生产者生产的数据可以继续存储下来。 但要保证,生产者生产的数据不能被重复消费。 一个
* 消费线程消费了,就不能被另一个消费线程消费了
*
* @author lihong 2016年1月1日 下午5:20:02
* @version v1.0
*/
public class Cache {
private static final Cache INSTANCE = new Cache();
private volatile List<User> queue = new LinkedList<User>();
// 没必要用AtomicReferenceFieldUpdater, 可以使用AtomicReference就好了
private static final AtomicReferenceFieldUpdater queueUpdater =
AtomicReferenceFieldUpdater.newUpdater(Cache.class, List.class, "queue");
private List<User> getQueue() {
return queue;
}
//唯一的生产者调用该方法
public static void produce(User user) {
INSTANCE.getQueue().add(user);
}
//多个消费者的调用该方法
public static List<User> consume() {
// volatile保证可见性后,但如果某几个消费线程是在同一瞬间调用重置队列方法,
// 结果很可能拿到了同一个老队列的引用,造成重复消费。使用CAS(compareAndSet),目的是不用锁,又能避免重复消费。
List<User> oldQueue = INSTANCE.getQueue();
List<User> newQueue = new LinkedList<User>();
while (!queueUpdater.compareAndSet(INSTANCE, oldQueue, newQueue)) {
oldQueue = INSTANCE.getQueue();
}
return oldQueue;
}
public class User {
}
}
一种重置生产者消费者模式的消费队列的线程安全的做法(java)
最新推荐文章于 2022-05-13 22:19:52 发布