Disruptor 2.0更新摘要

原文:Disruptor 2.0 – All Change Please 译者:杨帆

马丁最近发布了Disruptor的2.0版本,从我们开始将其开源以来发生了很多变化,现在是个时候推出一个正式的里程碑了。马丁的博客上涵盖了这次更新的所有内容,这篇文章的目的是尝试把我以前的博文以新框架的架构转述给大家,因为将它们都重写一遍要耗费很多时间。现在我看到手工绘图的缺点了。

阅读全文

深入理解Java内存模型(四)——volatile

本文属于作者原创,原文发表于InfoQ:http://www.infoq.com/cn/articles/java-memory-model-4

volatile的特性

当我们声明共享变量为volatile后,对这个变量的读/写将会很特别。理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个锁对这些单个读/写操作做了同步。下面我们通过具体的示例来说明,请看下面的示例代码:

class VolatileFeaturesExample {
    //使用volatile声明64位的long型变量
    volatile long vl = 0L;

    public void set(long l) {
        vl = l;   //单个volatile变量的写
    }

    public void getAndIncrement () {
        vl++;    //复合(多个)volatile变量的读/写
    }

    public long get() {
        return vl;   //单个volatile变量的读
    }
}

阅读全文

LMAX Disruptor——一个高性能、低延迟且简单的框架

原文地址:LMAX Disruptor – High Performance, Low Latency and Simple Too 翻译:杨帆 校对:丁一

Disruptor是一个用于在线程间通信的高效低延时的消息组件,它像个增强的队列,并且它是让LMAX Exchange跑的如此之快的一个关键创新。关于什么是Disruptor、为何它很重要以及它的工作原理方面的信息都呈爆炸性增长 —— 这些文章很适合开始学习Disruptor,还可跟着LMAX BLOG深入学习。这里还有一份更详细的白皮书

阅读全文

The j.u.c Synchronizer Framework翻译(二)设计与实现

原文链接 作者:Doug Lea 译者:欧振聪 校对:丁一

3 设计与实现

同步器背后的基本思想非常简单。acquire操作如下:

while (synchronization state does not allow acquire) {
	enqueue current thread if not already queued;
	possibly block current thread;
}
dequeue current thread if it was queued;

release操作如下:

update synchronization state;
if (state may permit a blocked thread to acquire)
	unblock one or more queued threads;

为了实现上述操作,需要下面三个基本组件的相互协作:

  • 同步状态的原子性管理;
  • 线程的阻塞与解除阻塞;
  • 队列的管理;

创建一个框架分别实现这三个组件是有可能的。但是,这会让整个框架既难用又没效率。例如:存储在队列节点的信息必须与解除阻塞所需要的信息一致,而暴露出的方法的签名必须依赖于同步状态的特性。

同步器框架的核心决策是为这三个组件选择一个具体实现,同时在使用方式上又有大量选项可用。这里有意地限制了其适用范围,但是提供了足够的效率,使得实际上没有理由在合适的情况下不用这个框架而去重新建造一个。 阅读全文

Qcon2012杭州站参会分享

作者:方腾飞  整理水羽哲

去年参加了QCon杭州2012大会,有一些收获和大家分享一下。

京东的分享

京东面临的问题

京东的分享嘉宾何斌提出京东之前面临的两个问题:第一个是促销时需要很多机器,但是平时不需要;第二个是当某一台客服中毒其他客服主机也会中毒。大家可以先思考下,觉得应该如何解决这两个问题呢?

京东的解决方案

第一个问题京东采用弹性架构的方式解决。当服务器的资源利用率超过一定阈值时动态扩展虚拟机。举一个例子:如在5分钟内资源使用率达到某个设定的阈值时,就会自动生成几个虚拟机,虚拟机里会自动部署好相关的应用程序,在自动发布前有一个TestServer来监测生成的虚拟机是否可以对外提供服务。云存储和云计算是分离的,云存储使用一个磁盘阵列来实现。

第二个问题京东采用桌面云的方式来解决。首先分配一批虚拟桌面池,然后客服通过权限登陆虚拟桌面,如果没有则再分配一批,虚拟桌面和人不是一一对应的,用完后就回到池子里别人可以继续申请使用,这样可以大大节约资源,当一台机器中病毒后只会影响到子网。

阅读全文

剖析Disruptor:为什么会这么快?(三)揭秘内存屏障

原文地址:http://ifeve.com/disruptor-memory-barriers/

译者:杜建雄     校对:欧振聪

最近我博客文章更新有点慢,因为我在忙着写一篇介绍内存屏障(Memory Barries)以及如何将其应用于Disruptor的文章。问题是,无论我翻阅了多少资料,向耐心的MartinMike请教了多少遍,以试图理清一些知识点,可我总是不能直观地抓到重点。大概是因为我不具备深厚的背景知识来帮助我透彻理解。

所以,与其像个傻瓜一样试图去解释一些自己都没完全弄懂的东西,还不如在抽象和大量简化的层次上,把我在该领域所掌握的知识分享给大家 。Martin已经写了一篇文章《going into memory barriers》介绍内存屏障的一些具体细节,所以我就略过不说了。

免责声明:文章中如有错误全由本人负责,与Disruptor的实现和LMAX里真正懂这些知识的大牛们无关。

阅读全文

Java NIO系列教程(十二) Java NIO与IO

原文地址:http://tutorials.jenkov.com/java-nio/nio-vs-io.html

作者:Jakob Jenkov   译者:郭蕾    校对:方腾飞

当学习了Java NIO和IO的API后,一个问题马上涌入脑海:

我应该何时使用IO,何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异、它们的使用场景,以及它们如何影响您的代码设计。

Java NIO和IO的主要区别

下表总结了Java NIO和IO之间的主要差别,我会更详细地描述表中每部分的差异。

IO                NIO
面向流            面向缓冲
阻塞IO            非阻塞IO
无                选择器

阅读全文

剖析Disruptor:为什么会这么快?(一)Ringbuffer的特别之处

原文地址:http://ifeve.com/ringbuffer/

作者:Trisha    译者寒桐  校对:方腾飞

最近,我们开源了LMAX Disruptor,它是我们的交易系统吞吐量快(LMAX是一个新型的交易平台,号称能够单线程每秒处理数百万的订单)的关键原因。为什么我们要将其开源?我们意识到对高性能编程领域的一些传统观点,有点不对劲。我们找到了一种更好、更快地在线程间共享数据的方法,如果不公开于业界共享的话,那未免太自私了。同时开源也让我们觉得看起来更酷。

从这个站点,你可以下载到一篇解释什么是Disruptor及它为什么如此高性能的文档。这篇文档的编写过程,我并没有参与太多,只是简单地插入了一些标点符号和重组了一些我不懂的句子,但是非常高兴的是,我仍然从中提升了自己的写作水平。

我发现要把所有的事情一下子全部解释清楚还是有点困难的,所有我准备一部分一部分地解释它们,以适合我的NADD听众。

首先介绍ringbuffer。我对Disruptor的最初印象就是ringbuffer。但是后来我意识到尽管ringbuffer是整个模式(Disruptor)的核心,但是Disruptor对ringbuffer的访问控制策略才是真正的关键点所在。

阅读全文

JVM运行时数据区

本文是《The Java Virtual Machine Specification (Java SE 7 Edition)》2011年6月版的运行时数据区的翻译

原文参见:http://download.oracle.com/javase/7/specs/jvms/JVMS-JavaSE7.pdf  译者:方腾飞

JVM定义了若干个程序执行期间使用的数据区域。这个区域里的一些数据在JVM启动的时候创建,在JVM退出的时候销毁。而其他的数据依赖于每一个线程,在线程创建时创建,在线程退出时销毁。

2.5.1  程序计数器(The pc Register

JVM一次能支持很多线程执行。每一个JVM线程有它自己的程序计数器。在任何时候,一个JVM的线程都正在执行当前线程的方法代码。如果这个方法不是本地方法,程序计数器包含当前被执行的JVM地址。如果线程正在执行本地方法,程序计数器的值为未定义。JVM 程序计数器足以存储一个返回地址或一个本地指针。

阅读全文

Java Fork Join 框架(三)实现

原文 http://gee.cs.oswego.edu/dl/papers/fj.pdf

作者:Doug Lea  译者Alex  校对:方腾飞

这个框架是由大约800行纯Java代码组成,主要的类是FJTaskRunner,它是java.lang.Thread的子类。FJTasks 自己仅仅维持一个关于结束状态的布尔值,所有其他的操作都是通过当前的工作线程来代理完成的。JFTaskRunnerGroup类用于创建工作线程,维护一些共享的状态(例如:所有工作线程的标示符,在偷取操作时需要),同时还要协调启动和关闭。

更多实现的细节文档可以在util.concurrent并发包中查看。这一节只着重讨论两类问题以及在实现这个框架的时候所形成的一些解决方案:支持高效的双端列表操作(push, pop 和 take), 并且当工作线程在尝试获取新的任务时维持偷取的协议。 阅读全文

深入理解java内存模型系列文章

深入理解java内存模型系列文章是本人在InfoQ发表的并发编程的连载文章。

  1. 深入理解java内存模型(一)——基础
  2. 深入理解java内存模型(二)——重排序
  3. 深入理解java内存模型(三)——顺序一致性
  4. 深入理解java内存模型(四)——volatile
  5. 深入理解java内存模型(五)——锁
  6. 深入理解java内存模型(六)——final
  7. 深入理解java内存模型(七)——总结

提纲

java线程之间的通信对程序员完全透明,内存可见性问题很容易困扰java程序员,本文试图揭开java内存模型神秘的面纱。本文大致分三部分:重排序与顺序一致性;三个同步原语(lock,volatile,final)的内存语义,重排序规则及在处理器中的实现;java内存模型的设计目标,及其与处理器内存模型和顺序一致性内存模型的关系。

深入理解Java内存模型(三)——顺序一致性

本文属于作者原创,原文发表于InfoQ:http://www.infoq.com/cn/articles/java-memory-model-3

数据竞争与顺序一致性保证

当程序未正确同步时,就会存在数据竞争。java内存模型规范对数据竞争的定义如下:

  • 在一个线程中写一个变量,
  • 在另一个线程读同一个变量,
  • 而且写和读没有通过同步来排序。

当代码中包含数据竞争时,程序的执行往往产生违反直觉的结果(前一章的示例正是如此)。如果一个多线程程序能正确同步,这个程序将是一个没有数据竞争的程序。

JMM对正确同步的多线程程序的内存一致性做了如下保证:

  • 如果程序是正确同步的,程序的执行将具有顺序一致性(sequentially consistent)–即程序的执行结果与该程序在顺序一致性内存模型中的执行结果相同(马上我们将会看到,这对于程序员来说是一个极强的保证)。这里的同步是指广义上的同步,包括对常用同步原语(lock,volatile和final)的正确使用。 阅读全文

深入理解Java内存模型(二)——重排序

本文属于作者原创,原文发表于InfoQ:http://www.infoq.com/cn/articles/java-memory-model-2

数据依赖性

如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性。数据依赖分下列三种类型:

名称 代码示例 说明
写后读 a = 1;b = a; 写一个变量之后,再读这个位置。
写后写 a = 1;a = 2; 写一个变量之后,再写这个变量。
读后写 a = b;b = 1; 读一个变量之后,再写这个变量。

上面三种情况,只要重排序两个操作的执行顺序,程序的执行结果将会被改变。

前面提到过,编译器和处理器可能会对操作做重排序。编译器和处理器在重排序时,会遵守数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序。

注意,这里所说的数据依赖性仅针对单个处理器中执行的指令序列和单个线程中执行的操作,不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑。

阅读全文

The j.u.c Synchronizer Framework翻译(一)背景与需求

原文链接 作者:Doug Lea 译者:欧振聪 校对:丁一

摘要

在J2SE 1.5的java.util.concurrent包(下称j.u.c包)中,大部分的同步器(例如锁,屏障等等)都是基于AbstractQueuedSynchronizer(下称AQS类)这个简单的框架来构建的。这个框架为同步状态的原子性管理、线程的阻塞和解除阻塞以及排队提供了一种通用机制。这篇论文主要描述了这个框架基本原理、设计、实现、用法以及性能。

阅读全文

伪共享(False Sharing)

原文地址:http://ifeve.com/false-sharing/

作者:Martin Thompson  译者:丁一

缓存系统中是以缓存行(cache line)为单位存储的。缓存行是2的整数幂个连续字节,一般为32-256个字节。最常见的缓存行大小是64个字节。当多线程修改互相独立的变量时,如果这些变量共享同一个缓存行,就会无意中影响彼此的性能,这就是伪共享。缓存行上的写竞争是运行在SMP系统中并行线程实现可伸缩性最重要的限制因素。有人将伪共享描述成无声的性能杀手,因为从代码中很难看清楚是否会出现伪共享。

为了让可伸缩性与线程数呈线性关系,就必须确保不会有两个线程往同一个变量或缓存行中写。两个线程写同一个变量可以在代码中发现。为了确定互相独立的变量是否共享了同一个缓存行,就需要了解内存布局,或找个工具告诉我们。Intel VTune就是这样一个分析工具。本文中我将解释Java对象的内存布局以及我们该如何填充缓存行以避免伪共享。
阅读全文

return top