这里的线程安全,是指一个读线程和一个写线程,读写两个线程是安全的,而不是说多个读线程和多个写线程是安全的。。

在程序设计中,我们有时会遇到这样的情况,一个线程将数据写到一个buffer中,另外一个线程从中读数据。所以这里就有多线程竞争的问题。通常的解决办法是对竞争资源加锁。但是,一般加锁的损耗较高。其实,对于这样的一个线程写,一个线程读的特殊情况,可以以一种简单的无锁RingBuffer来实现。这样代码的运行效率很高。

本文借鉴了Disruptor项目代码。

代码我在github上放了一份,需要的同学可以去下载(RingBuffer.java)。本文最后也会附上一份。

代码的基本原理如下。

如图所示,假定buffer的长度是bufferSize. 我们设置两个指针。head指向的是下一次读的位置,而tail指向的是下一次写的位置。由于这里是环形buffer (ring buffer),这里就有一个问题,怎样判断buffer是满或者空。这里采用的规则是,buffer的最后一个单元不存储数据。所以,如果head == tail,那么说明buffer为空。如果 head == tail + 1 (mod bufferSize),那么说明buffer满了。

接下来就是最重要的内容了:怎样以无锁的方式进行线程安全的buffer的读写操作。基本原理是这样的。在进行读操作的时候,我们只修改head的值,而在写操作的时候我们只修改tail的值。在写操作时,我们在写入内容到buffer之后才修改tail的值;而在进行读操作的时候,我们会读取tail的值并将其赋值给copyTail。赋值操作是原子操作。所以在读到copyTail之后,从head到copyTail之间一定是有数据可以读的,不会出现数据没有写入就进行读操作的情况。同样的,读操作完成之后,才会修改head的数值;而在写操作之前会读取head的值判断是否有空间可以用来写数据。所以,这时候tail到head - 1之间一定是有空间可以写数据的,而不会出现一个位置的数据还没有读出就被写操作覆盖的情况。这样就保证了RingBuffer的线程安全性。

最后附上代码供参考。欢迎批评指正,也欢迎各种讨论!

 1 public class RingBuffer {
2
3 private final static int bufferSize = 1024;
4 private String[] buffer = new String[bufferSize];
5 private int head = 0;
6 private int tail = 0;
7
8 private Boolean empty() {
9 return head == tail;
10 }
11 private Boolean full() {
12 return (tail + 1) % bufferSize == head;
13 }
14 public Boolean put(String v) {
15 if (full()) {
16 return false;
17 }
18 buffer[tail] = v;
19 tail = (tail + 1) % bufferSize;
20 return true;
21 }
22 public String get() {
23 if (empty()) {
24 return null;
25 }
26 String result = buffer[head];
27 head = (head + 1) % bufferSize;
28 return result;
29 }
30 public String[] getAll() {
31 if (empty()) {
32 return new String[0];
33 }
34 int copyTail = tail;
35 int cnt = head < copyTail ? copyTail - head : bufferSize - head + copyTail;
36 String[] result = new String[cnt];
37 if (head < copyTail) {
38 for (int i = head; i < copyTail; i++) {
39 result[i - head] = buffer[i];
40 }
41 } else {
42 for (int i = head; i < bufferSize; i++) {
43 result[i - head] = buffer[i];
44 }
45 for (int i = 0; i < copyTail; i++) {
46 result[bufferSize - head + i] = buffer[i];
47 }
48 }
49 head = copyTail;
50 return result;
51 }
52 }
 
 

线程安全的无锁RingBuffer的实现的更多相关文章

  1. 线程安全的无锁RingBuffer的实现【一个读线程,一个写线程】

    在程序设计中,我们有时会遇到这样的情况,一个线程将数据写到一个buffer中,另外一个线程从中读数据.所以这里就有多线程竞争的问题.通常的解决办法是对竞争资源加锁.但是,一般加锁的损耗较高.其实,对于 ...

  2. 高效线程池之无锁化实现(Linux C)

    from:http://blog.csdn.net/xhjcehust/article/details/45844901 笔者之前练手写过一个小的线程池版本(已上传至https://github.co ...

  3. (转)高效线程池之无锁化实现(Linux C)

    本文链接:https://blog.csdn.net/xhjcehust/article/details/45844901 笔者之前照着通用写法练手写过一个小的线程池版本,最近几天复习了一下,发现大多 ...

  4. 实现无锁的栈与队列(5):Hazard Pointer

    两年多以前随手写了点与 lock free 相关的笔记:1,2,3,4,质量都不是很高其实(读者见谅),但两年来陆陆续续竟也有些阅读量了(可见剑走偏锋的技巧是多容易吸引眼球).笔记当中在解决内存释放和 ...

  5. 基于无锁的C#并发队列实现(转载)

    最近开始学习无锁编程,和传统的基于Lock的算法相比,无锁编程具有其独特的优点,Angel Lucifer的关于无锁编程一文对此有详细的描述. 无锁编程的目标是在不使用Lock的前提下保证并发过程中共 ...

  6. 基于无锁的C#并发队列实现

    最近开始学习无锁编程,和传统的基于Lock的算法相比,无锁编程具有其独特的优点,Angel Lucifer的关于无锁编程一文对此有详细的描述. 无锁编程的目标是在不使用Lock的前提下保证并发过程中共 ...

  7. 一个无锁消息队列引发的血案(三)——地:q3.h 与 RingBuffer

    目录 (一)起因 (二)混合自旋锁 (三)q3.h 与 RingBuffer (四)RingQueue(上) 自旋锁 (五)RingQueue(中) 休眠的艺术 (六)RingQueue(中) 休眠的 ...

  8. .NET:通过 CAS 来理解数据库乐观并发控制,顺便给出无锁的 RingBuffer。

    背景 大多数企业开发人员都理解数据库乐观并发控制,不过很少有人听说过 CAS(我去年才听说这个概念),CAS 是多线程乐观并发控制策略的一种,一些无锁的支持并发的数据结构都会使用到 CAS,本文对比 ...

  9. 无锁,线程安全,延迟加载的单例实现(C#)

    单例(singleton)是非常常见,也非常有用的设计模式,当然了, 面试中也是经常会被问到的:)在几乎所有的项目中都能看到它的身影.简而言之,单例保证了一个自定义类型在整个程序的生命周期只被创建一次 ...

随机推荐

  1. CentOS配置Nginx+Tomcat7的多站点支持

    注:以下所有操作均在CentOS 6.5 x86_64位系统下完成. #准备工作# 在这之前需要先把Nginx和Tomcat安装好,具体见:<CentOS安装Nginx-1.6.2+安全配置&g ...

  2. android 生成验证码图片

    (转自:http://blog.csdn.net/onlyonecoder/article/details/8231373) package com.nobeg.util; import java.u ...

  3. Java中的序列化Serialable高级详解

    来自[http://blog.csdn.net/jiangwei0910410003/article/details/18989711] 引言 将 Java 对象序列化为二进制文件的 Java 序列化 ...

  4. hammer.js的六大事件

    1.Pan事件:在指定的dom区域内,一个手指放下并移动事件,即触屏中的拖动事件.这个事件在触屏开发中比较常用: Panstart 拖动开始 Panmove 拖动过程 Panend 拖动结束 Panc ...

  5. [WPF系列]-高级部分 Shadowed TextBox

    Download Solution ShadowedTextBoxExample.zip (70.3 KB) Usage <local:ShadowedTextBox Label="F ...

  6. 用CSS开启硬件加速来提高网站性能

    国外一篇文章,有点意思,转载过来,准备尝试下~ 中文地址:http://www.cnblogs.com/rubylouvre/p/3471490.html 原文地址:http://blog.teamt ...

  7. 团队项目——编写项目的Spec

    团队项目--编写项目的Spec 一.Spec的目标        spec主要用来说明软件的外部功能,和用户的交互情况,主要用来说明软件内部的设计.图片编辑器是与生活息息相关的一个必备软件,随的流行, ...

  8. TCP/IP四层模型和OSI七层模型

    TCP/IP四层模型 TCP/IP是一组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇.TCP/IP协议簇分为四层,IP位于协议簇的第二层(对应OSI的第三层),TCP位于协议簇的第三层(对 ...

  9. 洛谷11月月赛round.1

    太感动了#2 thwfhk 240 (801ms) 100 100 40   又一张明信片,话说10月的怎么还没收到   P2246 SAC#1 - Hello World(升级版) 题目背景 一天, ...

  10. Visual Studio 2013支持Xamarin的解决方案

    转自博客园[遗忘的代码] Xamarin的Visual Studio插件目前还不支持VS 2013,所以需要在安装Xamarin的VS插件时把2010和2012全选上 (由于我的电脑里只剩2013,而 ...