一种重置生产者消费者模式的消费队列的线程安全的做法(java)

/*
 * @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 {
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值