`
MauerSu
  • 浏览: 513752 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多
源:http://kenwublog.com/concurrent-no-lock-tech-tip
评:

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



需求:某代码块要求每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次。但基本也满足我的场景需要了。
分享到:
评论

相关推荐

    java高并发编程推荐超好的一本电子书

    下面将详细解释Java高并发编程的基础概念、核心技术以及实现技巧。 ### Java高并发编程基础 #### 1. 并发与并行的概念 - **并发**:是指在一段时间内多个程序或任务交替运行,从宏观上看似乎同时运行,但实际上...

    java并发技术

    - 这些类支持无锁操作,可以在高并发环境下高效地更新数值。 #### 4.3 线程安全集合 - `ConcurrentHashMap`:线程安全的哈希表,相比`synchronized`修饰的方法或代码块,具有更高的并发性能。 - `...

    JAVA并发编程实践高清版带书签PDF

    《JAVA并发编程实践》是一本深入探讨Java并发编程的权威指南,由Brian Goetz等作者撰写,这本书在Java开发者中享有很高的声誉。本书主要针对Java 5及更高版本的并发特性,涵盖了线程、锁、并发集合、原子变量、并发...

    关于并发

    在共享内存模型中,多个线程可以访问同一块内存,通过锁、信号量等机制实现同步。而在消息传递模型中,线程间通过发送和接收消息进行通信,这种方式能更好地保证数据的一致性,但可能增加通信开销。 **线程同步与...

    C++ Concurrency in Action 2012.03

    - **读写锁**:`std::shared_mutex`支持多个读线程共享资源的同时只允许一个写线程访问。 #### 五、内存模型与原子类型操作 ##### 5.1 内存模型 - C++11引入了一种统一的内存模型,它定义了线程之间如何一致地访问...

    maopao1.rar_cuda sort_cuda 排序_冒泡排序cuda_基于CUDA的加速

    本项目“maopao1”的代码提供了CUDA冒泡排序的一个实例,对于初学者来说,通过阅读和理解代码,可以深入学习CUDA编程的基本原理和技巧,了解如何将传统的CPU算法移植到GPU上进行加速。然而,为了获得更高的性能,...

    动态先入先出消息队列

    动态先入先出(FIFO)消息队列是一种常见的数据结构,它在计算机科学和IT领域中被广泛用于处理并发任务、数据交换以及系统间通信。...在实际开发中,理解其工作原理和优化技巧对于构建高性能的系统至关重要。

    Java多线程批量数据导入的方法详解.rar

    在Java编程中,多线程技术是实现高性能和并发处理的关键。当面临大量数据需要导入系统时,单线程处理可能会导致性能瓶颈,因此,利用多线程进行批量数据导入可以显著提高效率。本篇文章将深入探讨Java多线程批量数据...

    cpumemory_optimization_memory_cpucache_

    4. 并发优化:避免多线程间的缓存竞争,合理使用锁,考虑使用无锁数据结构。 5. 内存分配策略:根据数据生命周期选择合适的内存分配区域,如堆、栈或常量池。 六、总结 掌握内存优化和CPU缓存知识是程序员提升代码...

    demo memary

    标题“demo memary”似乎指的是一个关于内存管理的示例项目,而描述中的“赚积分、奉献自己的代码”可能是指这个项目是开源的,鼓励社区成员贡献代码来获取积分或荣誉。标签“内存管理”进一步确认了这个项目的核心...

    bigfile_parse:多线程并发解析大文件相关的源码-源码解析

    通过将大文件分割成多个小块,每个线程负责处理一个或多个数据块,从而实现并行处理。这大大减少了整体处理时间,尤其在多核处理器上效果显著。在"bigfile_parse"项目中,源码可能包括对线程池的使用,以及如何合理...

Global site tag (gtag.js) - Google Analytics