一个线程安全的计数器实现(java),可以让一个变量每天从1开始递增

Java ConcurrentHashMap:线程安全的哈希表实现 是Java集合框架中一颗璀璨的明珠,它通过巧妙的设计和高效的实现提供了无与伦比的并发性能。无论是早期的分段锁机制还是现代的CAS操作和树化技术,都展示了Java开发者对于并发编程的深刻理解和精湛技艺。在内部,它将整个哈希表分为多个段(Segment),每个段都是一个独立的锁,不同的线程可以持有不同段的锁,从而实现真正的并发访问。同时,它也采用了CAS(Compare-and-Swap)操作来减少锁的使用,从而提供了更高的吞吐量。CAS是一种无锁的技术,它可以在不阻塞线程的情况下更新共享变量的值。 阅读详情
前几天工作中一段业务代码需要一个变量每天从1开始递增。为此自己简单的封装了一个线程安全的计数器,可以让一个变量每天从1开始递增。当然了,如果项目在运行中发生重启,即便日期还是当天,还是会从1开始重新计数。所以把计数器的值存储在数据库中会更靠谱,不过这不影响这段代码的价值,现在贴出来,供有需要的人参考。
package com.hikvision.cms.rvs.common.util;



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

/**
 * Created by lihong10 on 2017/8/9.
 * 一个循环计数器,每天从1开始计数,隔天重置为1。
 * 可以创建一个该类的全局对象,然后每次使用时候调用其get方法即可,可以保证线程安全性
 */
public class CircularCounter {

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


    public CircularCounter() {
        /**
         * 这里将key设置为getCurrentDateString() + "sssssssssss" 是为了测试addAndGet()方法中日期发生变化的情况
         * 正常使用应该将key初始化为getCurrentDateString()
         */
        this.key = getCurrentDateString() + "sssssssssss";
        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, newDateStr);
        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, String newDateStr) {
        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;
        }
    }

    public static void test() {
        CircularCounter c = new CircularCounter();
        AtomicInteger count = new AtomicInteger(0);
        List<Thread> li = new ArrayList<Thread>();
        int size = 10;
        CountDownLatch latch1 = new CountDownLatch(1);
        CountDownLatch latch2 = new CountDownLatch(size);
        for (int i = 0; i < size; i++) {
            Thread t = new Thread(new CounterRunner(c, latch1, latch2, count), "thread-" + i);
            li.add(t);
            t.start();
        }
        System.out.println("start");
        latch1.countDown();

        try {
            latch2.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(count.get());
        System.out.println(c.get());
        if(count.get() == c.get()) {
            System.out.println("该计数器是线程安全的!!!");
        }

    }

    public static void main(String... args) {
        for(int i = 0; i < 15; i++) {
            test();
        }
    }


}


/**
 * 测试使用的Runnable对象
 */
class CounterRunner implements Runnable {
    private CircularCounter counter;
    private CountDownLatch latch1;
    private CountDownLatch latch2;
    private AtomicInteger count;

    public CounterRunner(CircularCounter counter, CountDownLatch latch1, CountDownLatch latch2, AtomicInteger count) {
        this.latch1 = latch1;
        this.latch2 = latch2;
        this.counter = counter;
        this.count = count;
    }

    @Override
    public void run() {

        try {
            latch1.await();
            System.out.println("****************");

            for (int i = 0; i < 20; i++) {
                counter.addAndGet();
                count.addAndGet(1);
            }
            latch2.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Java线程安全计数器 三种方式实现计数器1、简介说明 1、简介说明 这篇博客主要记录下Java在多线程情况下,集中线程安全的计数器的一个实现。主要使用了三种不同的方式实现。 synchronized方式,排它锁、独占锁、非公平锁,悲观锁 Lock方式,公平锁,非公平锁,悲观锁 CAS自旋锁,乐观锁,效率最高 代码: /** * 线程安全问题 * 计数器 */ public class Counters { /** * 利用synchronized关键字控制方法的原子性 * 排它锁、独占锁、 阅读详情

相关推荐

java使用线程安全的单例模式实现网站计数器

四个java类 附上代码(比较简单)用于设计模式课程需要 登录类 package mytest.demo.WebCount; public class Login implements Runnable { // 登录名称 private String loginName; public String getLoginName() { return loginName; } public void setLoginName(String loginN

qq_41582280的博客 4026

Java 使用redis 设计一个每天重新开始计数的计数器

你需要根据你的环境修改为正确的地址。你还需要在Java中引入Jedis依赖,例如使用Maven,你可以在。可以使用Redis的有序集合(Sorted Set)来实现一个每天重新开始计数的计数器。请注意,上述代码中连接到Redis的地址为。

qq_31532979的贺公子之数据科学与艺术博客,致力于科技向善,拥抱开源,要用技术的影响力来领导团队,而不是威权和职位! 1079

GD32 TIMER0 PWM输出死活没波形?别忘了这个关键配置(附完整代码)

本文详细解析了GD32 TIMER0 PWM输出无波形的常见问题,特别强调了高级定时器特有的主输出使能配置。通过完整的代码示例和调试技巧,帮助开发者快速解决PWM输出问题,适用于无刷电机控制等嵌入式应用场景。

weixin_30906185的博客 397

Java生成一定规则递增编号

项目需求中有时需要生成一定规则递增编号。例如生成设备编号:设备类型+五位编号(从1开始,不够前补0),也就是 SYXH000001 / SYXH00002 / SDOI00001 类似这样。 那么如何处理 000001 自增1变为 000002 呢?

蜗牛老师,专注编程领域 4万+

5G-A无源物联网:深度解析“不插电“智能的底层技术原理

北京移动推出5G-A无源物联网技术,实现电动车标签"零功耗"运行。该技术通过射频能量收集(利用5G-A基站高功率信号转换为电能)和反向散射通信(调制反射信号传输数据)两大核心技术,使设备无需电池即可工作。5G-A相比4G在信号能量密度、通信速率和定位精度等方面显著提升,结合通感一体等创新技术,为无源物联网提供商用基础。该方案已在北京小区试点应用,实现电动车精准定位管理,标签寿命可达5年以上。专家预测,这项技术将大幅降低物联网部署成本,推动"万物智联"时代的到来。

通信行业老兵、物联网从业者,做一个有趣的普通人。 2014

穿透鼠标实现后台点击,适用于任何窗口!【后台鼠标】【风雪】

也许你就是被这标题吸引来的,呵呵!好久没发帖了,勾引一下大家的胃口,当然有的人已经猜出原理了!既然来了,都要把原理学回家,不然就没意思了!很多游戏现在都不支持后台消息鼠标,要实现真的不是简单的,什么注入dll啊,什么hook俺也学不懂,那就简简单单另辟蹊径了下面来讲讲原理吧(下面的玩玩可以,用于实际不现实,俺也不藏了,看到这么多人回复,良心过意不去,呵呵)首先,将要点击的窗口上面覆盖的所有窗...

weixin_34129145的博客 1万+

Java面试题:实现简单的线程安全计数器

这个程序实现了一个简单的线程安全的计数器类 Counter,包含 increment 方法用于增加计数值,和 getCount 方法用于获取计数值。在 main 方法中,创建了一个计数器实例,并创建了多个线程对计数器进行增加操作。通过 synchronized 关键字,确保了在多线程环境下对计数器的操作是安全的。最终输出计数器的最终值。面试题:写一个Java程序,实现一个简单的线程安全的计数器类,包含增加和获取计数值的方法。

金木AI 866

基于Python实现基于遥感指数的水体提取

基于Python实现基于遥感指数的水体提取

gis收藏家的博客 6149

实现一个线程安全的计数器

package com.test; public class MySafeThread implements Runnable{ public static volatile int a; @Override public void run(){ while (true){ try { Thr...

麦子的博客 903

Zipformer在RK3588上的性能实测:比Conformer快多少?内存省多少?

本文在RK3588平台上对Zipformer和Conformer语音识别模型进行了全面的性能实测。结果显示,Zipformer在模型部署中展现出显著优势:推理速度比Conformer快约56%,峰值内存占用降低约60%,同时在AISHELL-1等测试集上保持了相当的识别准确率。这为边缘ASR应用提供了更高效、更节省资源的解决方案。

metal的博客 484

2025华为od面试手撕代码【求字符串表达式结果】

2025华为od面试手撕代码【求字符串表达式结果】

MISAYAONE的博客 1354

中级java每日一道面试题-2024年7月3日-机考篇(并发)-使用 Java 实现一个线程安全的计数器。

要实现一个线程安全的计数器,可以使用 synchronized 关键字来保证对计数器的操作是线程安全的。方法都使用了 synchronized 关键字来修饰,这确保了在多线程环境下,对计数器的操作是线程安全的。:使用 Java 实现一个线程安全的计数器。

qq_43071699的博客 545

C#面试题及详细答案120道(61-75)-- 多线程与异步

本文摘要了前后端面试题中关于线程与并发的核心知识点,包括线程与进程的区别(61题)、Thread/ThreadPool/Task的对比(62题)、线程安全实现方法(63题)、lock关键字的原理(64题)、Monitor类的进阶用法(65题)以及死锁的成因与避免(66题)。通过C#代码示例和表格对比,清晰展示了多线程编程的关键概念、应用场景及常见问题解决方案,适合开发者快速掌握面试高频考点。完整内容可访问专栏目录获取更多技术面试题解析。

大剑师兰特的GIS世界 1432

java创建计数器变量_一个线程安全的计数器实现(java),可以让一个变量每天从1开始递增...

package com.hikvision.cms.rvs.common.util;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.concurrent.CountDownLatch;import jav...

weixin_42365510的博客 837

【CANoe】CAPL_UDS安全算法dll制作

使用UDS进行刷写时,需要27服务解密后,才能正确执行刷写,本文提供两种制作27解密dll的方法,用于CANoe的CAPL脚本中。

星Yeah 的博客 1万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

java线程安全的计数器_Java线程安全计数器的简单代码示例

这篇文章主要介绍了Java线程安全的计数器简单实现代码示例,具有一定参考价值,需要的朋友可以了解下。前几天工作中一段业务代码需要一个变量每天从1开始递增。为此自己简单的封装了一个线程安全的计数器,可以让一个变量每天从1开始递增。当然了,如果项目在运行中发生重启,即便日期还是当天,还是会从1开始重新计数。所以把计数器的值存储在数据库中会更靠谱,不过这不影响这段代码的价值,现在贴出来,供有需要的人参考...

weixin_31669073的博客 860

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

java 线程安全 计数_Java线程安全的计数器简单实现代码示例

前几天工作中一段业务代码需要一个变量每天从1开始递增。为此自己简单的封装了一个线程安全的计数器,可以让一个变量每天从1开始递增。当然了,如果项目在运行中发生重启,即便日期还是当天,还是会从1开始重新计数。所以把计数器的值存储在数据库中会更靠谱,不过这不影响这段代码的价值,现在贴出来,供有需要的人参考。package com.hikvision.cms.rvs.common.util;import ...

weixin_39708854的博客 335

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

如何线程安全地实现一个计数器

i++是线程安全的吗   i++和++i的线程安全分为两种情况: 1、如果i是局部变量(在方法里定义的),那么是线程安全的。因为局部变量是线程私有的,别的线程访问不到,其实也可以说没有线程安不安全之说,因为别的线程对他造不成影响。 2、如果i是全局变量(类的成员变量),那么是线程不安全的。因为如果是全局变量的话,同一进程中的不同线程都有可能访问到。 如何线程安全地实现一个计数器 或者这...

不羁朔风的博客 4250

题目:如何线程安全的实现一个计数器?--youdaoyunbiji中Java面经

* 题目:如何线程安全的实现一个计数器? //在Java面经的5 个 答案集合中 //https://blog.youkuaiyun.com/puzimengya/article/details/81064455 * 思路:使用synchronized关键字修饰计数器方法 * 并且使用AtomicInteger类线程安全的一种原子操作的Inte...

weixin_43137176的博客 1208

设计线程安全的高性能计数器

方案适用场景优点缺点AtomicLong低并发,简单计数无锁,CAS 轻量级高并发时 CAS 自旋LongAdder高并发写,读少(推荐)分段累加,减少竞争sum()稍慢复杂逻辑,低性能要求简单易用锁竞争高时性能差极高吞吐,允许短暂不一致无竞争,性能极高读取可能不精确分片计数(如按 key 统计)扩展性强,支持多 key内存占用较高。

2203_75376529的博客 1613

java后台使用计数器实现轮询

现在遇到一个业务场景:有四个区域的若干用户。每天通过APP上传照片。四个区域每个区域各分配一个评分员对用户上传的照片进行评分,评分是匿名的,但为了确保公平公正,每个区域评分员又不能只对自己本区域的人员照片进行评分。同时每个评分员的评分工作量又要求大致相同。 这个场景下需要在用户评分时就指定相应的评分员,但这个指定是随机的,而每个评分员被指定的概率又是相同的。那么就可以考虑轮询。我这个场景是广义上的...

sinat_38220981的博客 3068

Java 什么是线程安全及如何实现线程安全

通过 JVM 内置锁(Monitor)实现互斥访问,确保同一时间只有一个线程执行临界区代码。:基于 CAS(Compare-and-Swap)实现无锁线程安全操作,适用于简单原子操作。理解线程安全的三要素(原子性、可见性、有序性)是解决多线程问题的关键。死锁(Deadlock):多个线程互相等待对方释放锁,导致永久阻塞。:保证变量的可见性和禁止指令重排序,但不保证原子性。:操作不可分割,要么全部完成,要么全部不执行。更灵活的锁控制(如可中断、超时、公平锁)。单一变量的原子操作(如计数器、标志位)。

m0_37145844的博客 2121

Java线程安全问题

共享资源是指,同时会有多个线程访问的资源。

fggdgh的博客 1097

Java线程安全的计数器

一、多线程以及线程安全           java线程安全就是指控制多个线程对某个资源的有序访问或修改。这涉及两个很重要的概念:java的内存模型和java的线程同步机制。       1.java的内存模型 要解决两个主要的问题:可见性和有序性 可见性: 多个线程之间是不能互相传递数据通信的,它们之间的沟通只能通过共享变量来进行       2.线程同步        由于同一

Yolanda_NuoNuo的专栏 1万+

【Java并发】变量的内存存储、线程安全分析

也就意味着不同作用域的局部变量是不共享的。UserDaoImpl中的update方法中的 conn 是局部变量,并且没有逃离方法的作用范围,所以 conn是线程安全的,UserServiceImpl 中的 UserDao是成员变量,但是userDao它调用的方法是线程安全的,所以userDao也是线程安全的,同理,userService也是线程安全的。conn是成员变量,多个线程用的是同一个conn,所以是线程不安全的,同时 userDao 也是线程不安全的,userService也是线程不安全的。

qq_39666711的博客 1384
上一篇: netty - ThreadDeathWatcher用法测试
下一篇: mybatis之XMLLanguageDriver使用方式例子
lhever_
博客等级 码龄14年 213粉丝 130原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值