线程隔离计数器



import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 * 线程安全的计数器(线程之间相互隔离)
 */
public class CircularCounterThread {

    private static final AtomicReferenceFieldUpdater<CircularCounterThread, AtomicInteger> valueUpdater =
            AtomicReferenceFieldUpdater.newUpdater(CircularCounterThread.class, AtomicInteger.class, "value");
    //保证内存可见性
    private volatile String key;

    //保证内存可见性
    private volatile AtomicInteger value;

    private static final String DATE_PATTERN = "yyyy-MM-dd";

    // ThreadLocal 来为每个线程创建独立的 CircularCounter 实例
    private static final ThreadLocal<CircularCounterThread> threadLocalCounter = ThreadLocal.withInitial(CircularCounterThread::new);

    public CircularCounterThread() {
        /**
         * 这里将key设置为getCurrentDateString() + "Thread-8(当前线程名称)" 是为了测试addAndGet()方法中日期发生变化的情况
         * 正常使用应该将key初始化为getCurrentDateString()
         */
        this.key = getCurrentDateString() + Thread.currentThread().getName();
        this.value = new AtomicInteger(0);
    }

    /**
     * 获取计数器加1以后的值
     *
     * @return
     */
    public Integer addAndGet() {

        AtomicInteger oldValue = value;
        AtomicInteger newInteger = new AtomicInteger(0);

        int newVal = -1;
        String newDateStr = getCurrentDateString();
        //日期一致,计数器加1后返回
        if (isDateEquals(newDateStr)) {
            newVal = add(1);
            return newVal;
        }

        //日期不一致,保证有一个线程重置技术器
        reSet(oldValue, newInteger);
        this.key = newDateStr;
        //重置后加1返回
        newVal = add(1);
        return newVal;
    }

    /**
     * 获取计数器的当前值
     *
     * @return
     */
    public Integer get() {
        return value.get();
    }


    /**
     * 判断当前日期与老的日期(也即key成员变量记录的值)是否一致
     *
     * @return
     */
    private boolean isDateEquals(String newDateStr) {
        String oldDateStr = key;
        if (!isBlank(oldDateStr) && oldDateStr.equals(newDateStr)) {
            return true;
        }

        return false;
    }

    /**
     * 如果日期发生变化,重置计数器,也即将key设置为当前日期,并将value重置为0,重置后才能接着累加,
     */
    private void reSet(AtomicInteger oldValue, AtomicInteger newValue) {
        if (valueUpdater.compareAndSet(this, oldValue, newValue)) {
            System.out.println("线程" + Thread.currentThread().getName() + "发现日期发生变化");
        }
    }

    /**
     * 获取当前日期字符串
     *
     * @return
     */
    private String getCurrentDateString() {
        Date date = new Date();
        String newDateStr = new SimpleDateFormat(DATE_PATTERN).format(date);
        return newDateStr;
    }

    /**
     * 计数器的值加1。采用CAS保证线程安全性
     *
     * @param increment
     */
    private int add(int increment) {
        return value.addAndGet(increment);
    }

    public static boolean isBlank(CharSequence cs) {
        int strLen;
        if (cs != null && (strLen = cs.length()) != 0) {
            for (int i = 0; i < strLen; ++i) {
                if (!Character.isWhitespace(cs.charAt(i))) {
                    return false;
                }
            }

            return true;
        } else {
            return true;
        }
    }

    // 获取当前线程的 CircularCounter 实例
    public static CircularCounterThread getCurrentThreadCounter() {
        return threadLocalCounter.get();
    }
}

线程之间互相隔离,个人感觉有点多此一举了,懒得改了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星梦客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值