首页 > 其他分享 >高并发无锁实现代码块只进入一次小技巧

高并发无锁实现代码块只进入一次小技巧

时间:2023-04-20 11:38:18浏览次数:37  
标签:set 技巧 并发 无锁 线程 AtomicLong new Holder public


评:

[quote]Holder.count.set(0) 会出现 ABA的问题,new也是解决不了问题的
除非假设 代码块执行时间长些,或者对时间的控制更精确
new 临时解决了问题 只是说明 执行new操作 cpu花费的时间长一些
假如同步代码块内假如等待3秒代码,set(0)也可以实现此需求[/quote]


需求:某代码块要求每5秒只进入一次,并且在5秒边界处存在高并发。

public class Test { 


 public static void main(String[] args) throws InterruptedException { 

 final CyclicBarrier barrier = new CyclicBarrier(50); // 50个并发 

 final long interval = 5000; // 每5秒 

 Holder.time.set(System.currentTimeMillis());// 起始时间 


 for (int i = 0; i < 100; i++) { 

 new Thread() { 


 @Override 

 public void run() { 

 while (true) { 

 long now = System.currentTimeMillis(); 

 // 时间原子操作+原子计数器实现无锁单线程进入 

 if (now - Holder.time.get() > interval && Holder.count.incrementAndGet() == 1) { 

 System.out.println("function block entered"); 

 Holder.time.set(now); 

 Holder.count = new AtomicLong(); 

 } 

 } 

 } 


 }.start(); 

 } 

 } 


 static class Holder { 

 public static volatile AtomicLong time = new AtomicLong(); 

 public static AtomicLong count = new AtomicLong(); 

 } 


}



其实思路也比较简单,首先通过计数器保证同一时刻只能进入一个线程,然后重置时间,最后重置计数器,亮点是计数器的重置只能通过new,不能set(0),set(0)会导致同一时刻其余并发线程看到0值,从而误进入代码块。而new可以保证其他并发线程一直hold在老的对象上累加,new只对后面的新线程起到可见性(volatile),加上之前的时间已经重置,条件判断里能严格保证代码块只进入一次。

当然,这种情况也只能保证99.9%的场景,在多核场景下如果系统做了CPU指令重排序后,那就有可能不止一次进入,我通过压测1000个线程,就出现过1次进入了2次。但基本也满足我的场景需要了。

标签:set,技巧,并发,无锁,线程,AtomicLong,new,Holder,public
From: https://blog.51cto.com/u_16080829/6209261

相关文章

  • 心法|大型高并发系统的逃生能力架构要如何设计
    故障是无法避免的,所以作为一个大型互联网系统,逃生能力的架构设计尤其重要,一个具备优秀逃生能力的系统,在故障发生后,可以把用户影响降到最低甚至无损,多年在小爱/米家一次次大小故障的处理和复盘中,慢慢形成了一些经验和方法的思考。大型互联网系统,模块多、依赖关系和运行环境复杂,逃......
  • 助你掌握搜索神器,10个实用的Elasticsearch查询技巧
    前言  Elasticsearch是一个非常流行的搜索引擎,已经成为了许多企业的首选解决方案。然而,我们要想成为一个优秀的程序员,就必须掌握各种查询技巧。本文将向大家介绍10个实用的Elasticsearch查询技巧,并配上详细的代码示例,帮助我们更好地掌握Elasticsearch的查询语法。示例1.匹......
  • Fiddler使用技巧
    【Fiddler使用技巧】:弱网测试: 首先打开Fiddler,Rules->Performance->勾选SimulateModemSpeeds然后快捷键Ctrl+R打开设置窗口,设置speeds在if(m_SimulateModem){//Delaysendsby300msperKBuploaded.释义:每1kb上传/下载所需时间为0.3soSession["request-trickle-delay......
  • hdoj The sum problem 2058 (数学等差公式&技巧转换)
    ThesumproblemTimeLimit:5000/1000MS(Java/Others)    MemoryLimit:32768/32768K(Java/Others)TotalSubmission(s):21416    AcceptedSubmission(s):6287ProblemDescriptionGivenasequence1,2,3,......N,yourjob......
  • quartz简单实现多任务并发
    packagecom.scan.xxx.config.quartz;importlombok.extern.slf4j.Slf4j;importorg.quartz.*;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Co......
  • 关于dev report 报表模版数据源过滤的一点技巧
    有了报表,能使用保存展示模版,能加载数据源了.能正常展示了.我们可能还有个需求,想在窗体上加个下拉,过滤报表内的数据,比如只显示某类.经过多次测试失败,最后发现数据源应该是下边的操作方法 publicstaticList<xxx>infos=newList<xxx>();我们不能直接 infos=infos......
  • DataGrid应用技巧两则(downmoon)---列求和与列字段转换
    DataGrid应用技巧两则(downmoon)---列求和与列字段转换<scriptlanguage="javascript"type="text/javascript">document.title="DataGrid应用技巧两则(downmoon)---列求和与列字段转换-"+document.title</script>DataGrid应用技巧两则(downmoon)一:增加求和列: pri......
  • 关于PythonNet与TensorFlow的调试技巧
    1.使用TensorFlow2.x版本训练的模型,在导入时容易报错,不要跨版本训练或者调用模型。报错内容通常定位到restore方法。2.PythonNet调用py文件报错时,右键该文件执行后报错内容会一闪而过,可以右键使用Python编译器(Idel)打开,错误会详细显示,且内容与编辑器一样。3.TensorFlow1.9最......
  • gdb 调试技巧:定位程序卡死问题
     gdb调试技巧:定位程序卡死问题 最近遇到一个程序卡死的问题,借助gdb轻松定位,供大家参考。遇到程序卡死不退处,可能不知道卡死在什么地方,如果程序非常简单,也许printf大法就可以很快定位。但是对于大型程序,尤其是一些框架程序,printf大法可能就力不从心了。实际的程序......
  • AI测试101:测试AI系统的实用技巧&ML和AI自动化工具
    基于人工智能的系统,也称为神经网络(NNNeuralNetworks),和其他应用程序一样是"系统",因此需要测试。本文将指导你测试AI和基于NN的系统,并理解相关概念。测试人工智能系统的不同之处是什么?"传统"的软件是建立在内部确定的算法基础上的。例如,对于将摄氏度转换为华氏度的系统,它将使......