原文链接 Netty中ByteBuf的引用计数线程安全的实现原理

代码仓库地址

ByteBuf 实现了ReferenceCounted 接口,实现了引用计数接口,该接口的retain(int) 方法为了保证线程安全使用了自旋锁来确保操作安全,那么选择了比较重要的实现类AbstractReferenceCountedByteBuf 来查看这一特性.

在JDK 1.5 之后,JDK的并发包提供了Atomic* 的相关类,来帮助开发者更好的完成并发操作,这里我们学习使用CAS来实现线程安全,CAS就是ComposeAndSet,中文含义,比较And更新,我们来看一个例子,具体的说明在注释中!

static class Increment {

    // volatile 保证了线程可见性,但是没有保证按成安全性
private volatile int i; // 声明CAS的抽象类
private static AtomicIntegerFieldUpdater<Increment> updater; static {
// 通过静态方法创建CAS的具体实例
// 第一个参数表示维护的Integer所在的类的class
// 第二个参数表示维护的Integer变量的名称
updater = AtomicIntegerFieldUpdater.newUpdater(Increment.class, "i");
} /**
* 构造初始化函数
*
* @param i
*/
public Increment(int i) {
this.i = i;
} /** 自增一个 */
public void increment() {
increment(1);
} /**
* 重载自增方法
*
* <p>该方法具体实现了CAS的代码逻辑,重在均在下面的for循环中
*
* @param increment
*/
public void increment(int increment) {
// 创建一个死循环,compareAndSet检查不通过的时候,重新获取新的值尝试更新
for (; ; ) {
// 保存当前线程更新的值的状态
int oldI = this.i;
final int newValue = oldI + increment;
// 校验值是否更新完成
if (newValue <= increment) {
throw new IllegalArgumentException("非法的参数异常");
}
// 如果CAS更新完成,则退出循环,否则打印重试日志
if (updater.compareAndSet(this, oldI, newValue)) {
break;
}
System.out.println("发生多线程并发,CAS正常重新尝试");
}
}
}

实现了自增的CAS代码之后,我们创建一个MyRunnable 继承Runnable 在run() 方法中实现Increment 实例的自增,具体代码如下:

  static class MyRunnable implements Runnable {

    private Increment increment;

    public MyRunnable(Increment increment) {
this.increment = increment;
} @Override
public void run() {
increment.increment();
}
}

在main() 方法中我们创建一个Increment 示例对象,构造参数传1,然后创建50个线程,同时启动,观察最终的结果, 多次运行观察是否能实现线程安全.

  public static void main(String[] args) throws InterruptedException {
Increment increment = new Increment(1);
for (int i = 0; i < 50; i++) {
new Thread(new MyRunnable(increment)).start();
}
// 延时4s, 等待所有线程执完成后,输出i
TimeUnit.SECONDS.sleep(4);
System.out.println(increment.i);
}

最后输出结果为51,可见CAS 能够实现多线程安全的问题,相对于RelockCount和重量级的synchronized 各有各的适合场景,下面回到Netty的自旋锁的问题上来,可以看到下面的代码和上面的示例是类似的,Netty依靠这个方法来完成ByteBuf的引用计数,确保多线程操作ByteBuf的时候引用计数不会出现多线程的问题,

下面的代码是引用了Netty5 的 io.netty.buffer.AbstractReferenceCountedByteBuf 类的部分代码,有兴趣的朋友可以下载该框架的源码,找到该文件看一下。

    private static final AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> refCntUpdater;
static {
AtomicIntegerFieldUpdater<AbstractReferenceCountedByteBuf> updater =
PlatformDependent.newAtomicIntegerFieldUpdater(AbstractReferenceCountedByteBuf.class, "refCnt");
if (updater == null) {
updater = AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCountedByteBuf.class, "refCnt");
}
refCntUpdater = updater;
} @Override
public ByteBuf retain(int increment) {
if (increment <= 0) {
throw new IllegalArgumentException("increment: " + increment + " (expected: > 0)");
}
for (;;) {
int refCnt = this.refCnt;
if (refCnt == 0) {
throw new IllegalReferenceCountException(0, increment);
}
if (refCnt > Integer.MAX_VALUE - increment) {
throw new IllegalReferenceCountException(refCnt, increment);
}
if (refCntUpdater.compareAndSet(this, refCnt, refCnt + increment)) {
break;
}
}
return this;
}

Netty中ByteBuf的引用计数线程安全的实现原理的更多相关文章

  1. 【Netty官方文档翻译】引用计数对象(reference counted objects)

    知乎有关于引用计数和垃圾回收GC两种方式的详细讲解 https://www.zhihu.com/question/21539353 原文出处:http://netty.io/wiki/referenc ...

  2. OC中的自动引用计数

    目录: 1,自动引用计数的定义 2,强引用和弱引用 3,类比手动引用 4,循环引用 5,CoreFoundation 内容: 自动引用计数的定义: (Automatic Reference Count ...

  3. Netty中ByteBuf 的零拷贝

    转载:https://www.jianshu.com/p/1d1fa2fe1ed9 此文章已同步发布在我的 segmentfault 专栏. 根据 Wiki 对 Zero-copy 的定义: &quo ...

  4. Netty源码分析之ByteBuf引用计数

    引用计数是一种常用的内存管理机制,是指将资源的被引用次数保存起来,当被引用次数变为零时就将其释放的过程.Netty在4.x版本开始使用引用计数机制进行部分对象的管理,其实现思路并不是特别复杂,它主要涉 ...

  5. netty中的ByteBuf

    网络数据的基本单位总是字节.Java NIO 提供了 ByteBuffer 作为它 的字节容器,但是这个类使用起来过于复杂,而且也有些繁琐. Netty 的 ByteBuffer 替代品是 ByteB ...

  6. netty系列之:不用怀疑,netty中的ByteBuf就是比JAVA中的好用

    目录 简介 ByteBuf和ByteBuffer的可扩展性 不同的使用方法 性能上的不同 总结 简介 netty作为一个优秀的的NIO框架,被广泛应用于各种服务器和框架中.同样是NIO,netty所依 ...

  7. netty 引用计数对象(reference counted objects)

    [Netty官方文档翻译]引用计数对象(reference counted objects) http://damacheng009.iteye.com/blog/2013657

  8. netty中的channelPipeline在编程中的作用

    在netty编程中我们绝大多数是要是用nio的,nio相比传统的io更加高效,而nio中核心概念离不开channel,buffer,selector三个重要的对象. 那么在netty中有一个chann ...

  9. 【Netty】Netty之ByteBuf

    一.前言 前面已经学习了Netty中传输部分,现在接着学习Netty中的ByteBuf. 二.ByteBuf 2.1 ByteBuf API 在网络上传输的数据形式为Byte,Java NIO提供了B ...

随机推荐

  1. ArcGIS API for JavaScript 4.x 本地部署之跨域问题解决法:CORS

    众所周知,在离线部署ArcGIS API for JavaScript时,有时候会产生微件上的字体.符号变成方框的问题.这是遇到了跨域,只需要对所在服务器进行配置即可. 本篇使用的环境是:API配置在 ...

  2. SQLite新建数据库及txt文件(CSV文件)导入

    1.安装准备: Windows系统环境: 安装:SQLiteExpert  及 官网的SQLite tool  我们要用到其中的SQLite.exe       地址:https://www.sqli ...

  3. (四)图数据neo4j用户管理

    1.用户管理 neo4j可通过内置函数,进行用户的创建.查看.删除. (1)用户创建; CALL dbms.security.createUser(name,password,requridchang ...

  4. navicate for mysql之-Can't connect to MySQL server on 'localhost'(10038)

    1. 卸载navicate for mysql 会留下很多坑,主要是卸载不干净,卸载之后重新安装会出现之前的库内容和库链接还存在的问题,这种情况的出现是卸载残余. 解决办法,清理注册表(网上很多教程但 ...

  5. Windows-删除Windows Server backup卷影副本

    现有环境中有一台Windows Server做过定期备份计划,时间太久未做清理操作,收到磁盘报警邮件后需要及时释放该空间,具体操作步骤如下: 当前备份计划信息如下: 清理步骤如下: 1.以管理身份运行 ...

  6. vue 过滤器 基本用法

    使用地点:双花括号插值和v-bind表达式. <div id="app"> <p>{{ message|capitalize}}</p> < ...

  7. php实现中文字符串无乱码截取

    在PHP开发中会经常用到字符串截取,有的时候字符串截取会出现乱码的情况,那么怎么解决这个问题呢,其实也很容易 首先我们要了解关于中英文占多少字节的问题. ASCII码:一个中文汉字占两个字节的空间. ...

  8. chrome谷歌浏览器开发者工具-网络带宽控制

    有时候我们想在本地测试一下图片预加载loading的加载情况,如下图: 可无奈一般网络带宽都比较好,基本上看不到效果,图片一下子就加载出来了, 可能这个时候有些小伙伴想到的办法是用定时器延迟加载 其实 ...

  9. Vue(day5)

    一.监听数据变化的三种形式 假设我们需要提供两个输入框,分别输入姓和名,然后自动拼接为姓名.这样,我们就需要监听输入框的数据变化,让完整的姓名跟随输入的变动而变化.我们可以使用以下三种方式: 1.结合 ...

  10. win10启动远程桌面连接的设置

    现在win10系统用的非常普遍,做项目的时候,也经常将一台win10系统的机器当作服务器使用.这就涉及到利用远程桌面登录到win10系统的问题,有几次利用远程桌面登录win10系统的设置经历,好像每次 ...