/*
* @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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.