Slipped Conditions

原文链接 作者:Jakob Jenkov 译者:余绍亮 校对:丁一

所谓Slipped conditions,就是说, 从一个线程检查某一特定条件到该线程操作此条件期间,这个条件已经被其它线程改变,导致第一个线程在该条件上执行了错误的操作。这里有一个简单的例子:

[code lang=”java”]
public class Lock {
private boolean isLocked = true;

public void lock(){
synchronized(this){
while(isLocked){
try{
this.wait();
} catch(InterruptedException e){
//do nothing, keep waiting
}
}
}

synchronized(this){
isLocked = true;
}
}

public synchronized void unlock(){
isLocked = false;
this.notify();
}
}
[/code]
阅读全文

CPU缓存刷新的误解

原文地址  作者:Mechanical Sympathy  译者:潘曦  校对:Simon-SZ ,方腾飞

即使是资深的技术人员,我经常听到他们谈论某些操作是如何导致一个CPU缓存的刷新。看来这是关于CPU缓存如何工作和缓存子系统如何与执行核心交互的一个常见误区。本文将致力于解释CPU缓存的功能以及执行程序指令的CPU核心如何与缓存交互。我将以最新的Intel x86 CPU为例进行说明,其他CPU也使用相似技术以达到相同目的。

绝大部分常见的现代系统都被设计成在多处理器上共享内存。共享内存的系统都有一个单独的内存资源,它会被两个或者更多的独立CPU核心同时访问。核心到主存的延迟变化范围很大,大约在10-100纳秒。在100ns内,一个3GH的CPU可以处理多达1200条指令。每一个Sandy Bridge的CPU核心,在每个CPU时钟内可以并行处理4条指令。CPU使用缓存子系统避免了处理核心直接访问主存的延迟,这样能使CPU更高效的处理指令。一些缓存很小、非常快速并且集成在每个核心之内;而另一些则慢一些、更大、在各个核心间共享。这些缓存与寄存器和主内存一起构成了非持久性的内存体系。 阅读全文

Memory Access Patterns Are Important

原文地址:http://mechanical-sympathy.blogspot.com/2012/08/memory-access-patterns-are-important.html(因墙转载)

In high-performance computing it is often said that the cost of a cache-miss is the largest performance penalty for an algorithm.  For many years the increase in speed of our processors has greatly outstripped latency gains to main-memory.  Bandwidth to main-memory has greatly increased via wider, and multi-channel, buses however the latency has not significantly reduced.  To hide this latency our processors employ evermore complex cache sub-systems that have many layers.

The 1994 paper “Hitting the memory wall: implications of the obvious” describes the problem and goes on to argue that caches do not ultimately help because of compulsory cache-misses.  I aim to show that by using access patterns which display consideration for the cache hierarchy, this conclusion is not inevitable.
阅读全文

Memory Barriers/Fences

原文地址:http://mechanical-sympathy.blogspot.com/2011/07/memory-barriersfences.html(因墙转载)

In this article I’ll discuss the most fundamental technique in concurrent programming known as memory barriers, or fences, that make the memory state within a processor visible to other processors.

CPUs have employed many techniques to try and accommodate the fact that CPU execution unit performance has greatly outpaced main memory performance.  In my “Write Combining” article I touched on just one of these techniques.  The most common technique employed by CPUs to hide memory latency is to pipeline instructions and then spend significant effort, and resource, on trying to re-order these pipelines to minimise stalls related to cache misses.

When a program is executed it does not matter if its instructions are re-ordered provided the same end result is achieved.  For example, within a loop it does not matter when the loop counter is updated if no operation within the loop uses it.  The compiler and CPU are free to re-order the instructions to best utilise the CPU provided it is updated by the time the next iteration is about to commence.  Also over the execution of a loop this variable may be stored in a register and never pushed out to cache or main memory, thus it is never visible to another CPU. 阅读全文

话说模式匹配(4) scala里的赋值语句都是模式匹配吗?

先抛个问题,下面的语句是否都合理(编译通过),哪些会引起模式匹配?

scala> val a = 100 
scala> val A = 100 
scala> val a@b = 100
scala> val (a,b) = (100,200)
scala> val (a,B) = (100,200)    //第二个变量大写
scala> val Array(a,b) = Array(100,200)
scala> val Array(a,B) = Array(100,200) 

scala> object Test { val 2 = 2 } 
scala> object Test { val 2 = 3 } 

我们先看看其他语言(对scala有影响的)有关赋值语句的定义:

1) 在 ML 语言里,对赋值语句的定义:
val P = E

表示定义了模式P中的变量,并赋予它们表达式E中相应的值。

2) 在Erlang中等号 = 表示一个模式匹配操作

在这两种语言中,赋值语句都明确的定义为模式匹配,那么scala中,所有的赋值语句是否都是模式匹配呢?
尤其scala可以说在函数式风格上与ML(及其家族)语言有某种血缘,在这一点上是否也与ML完全一致呢?

先分析一下上面的每条赋值语句:val a = 100val A = 100是直观且没有歧义的。

val a@b = 100 是什么意思?回忆一下第一篇里讲过的“变量绑定模式”,当时的例子有点复杂,重新理解一下:

//给"hello"字符串对象用v1这个变量名
scala> "hello" match { case v1 => println(v1) }

//变量绑定模式,把变量v2 绑定在v1这个模式上
scala> "hello" match { case v2@v1 => println(v2) }

上面的例子中,第一行中v1是个变量模式。 第二行中v2是一个新的变量,只有在v1这个模式匹配成功的情况下,才会把自己绑定到v1上,而v1因为是一个变量模式,它总能匹配成功,所以这里v2也会绑定到”hello”对象上。变量绑定模式通常不会这么使用,更多用在绑定到一个复合结构的模式上,如:

scala> List(1,List(2,3)) match { case List(_, x@List(2,_*)) => println(x.size) }
2

把变量x绑定到了嵌套的 List(2,3) 这个对象上

但赋值语句val a@b = 100 跟上面的有关系么?我们通过ToolBox看看它”脱糖”后的语法树:

scala> tb.parse("val a@b=100")
res13: tb.u.Tree =
{
    <synthetic> private[this] val x$3 = 100: @scala.unchecked match {
        case (a @ (b @ _)) => scala.Tuple2(a, b) //这一句
    };
    val a = x$3._1;
    val b = x$3._2
}

有注释的那一句里面把a,b两个局部变量绑定到通配符”_”上,而这个通配符模式case _ => 可以匹配任何对象,所以相当于把a,b两个变量绑定到了100这个对象上,并产生了一个二元组记录这两个局部变量值。最终把二元组里的值分别赋给了我们定义的a,b两个变量。

接下来的val (a,b) = (100,200) 这个赋值也容易理解,把二元组里的值分别赋给a,b两个变量么,也是经过模式匹配的么?继续用ToolBox分析:

scala> tb.parse("val (a,b)=(100,200)")
res14: tb.u.Tree =
{
    <synthetic> private[this] val x$4 = scala.Tuple2(100, 200): @scala.unchecked match {
        case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2(a, b)
    };
    val a = x$4._1;
    val b = x$4._2
}

看到了,是一个构造器模式与变量绑定模式的混合模式匹配。

再下一个val (a,B) = (100,200) 这个与上一个有区别么?回顾一下第一篇里讲到的“常量模式”:当变量大写时将被对待为常量模式,也就是说 大写B 和上面的 小写b 是两种不同的模式!!

scala> tb.parse("val (a,B)=(100,200)")
res15: tb.u.Tree =
val a = scala.Tuple2(100, 200): @scala.unchecked match {
    case scala.Tuple2((a @ _), B) => a
} 

大写B在这里当作常量来解析,但又找不到B这个变量(除非之前有定义过),就报错了:

scala> val (a,B) = (100,200)
<console>:8: error: not found: value B
   val (a,B) = (100,200)
          ^

后边两个Array的赋值语句与这两个类似,小括号写法只是元组(Tuple)的语法糖而已。

最后,真正有趣,且会让新手崩溃的情况 object Test { val 2 = 2 } 为什么这个编译和初始化都没问题?

scala> object Test { val 2 = 2 }
defined module Test

scala> Test
res16: Test.type = Test$@3042dc22

简直逆天,难道这个背后也与模式匹配有关系么?

scala> tb.parse(" object Test { val 2 = 2 }")
res0: tb.u.Tree =
object Test extends scala.AnyRef {
    def <init>() = {
        super.<init>();
        ()
    };
    <synthetic> private[this] val x$1 = 2: @scala.unchecked match {
        case 2 => ()
    }
}

确实又是一个常量模式匹配,2匹配2,成功。

同理,下一个 object Test { val 2 = 3 } 也是个常量模式匹配,但为何明显不匹配,却可以编译时成功,而运行时时才报错呢?

scala> object Test { val 2 = 3 }
defined module Test

scala> Test
scala.MatchError: 3 (of class java.lang.Integer)
    at Test$.<init>(<console>:8)

这是因为object 是惰性初始化的原因(lazy),如下:

// 对下面的单例
object Test { val a = 2 }

$ scalac -Xprint:jvm A.scala
package <empty> {
  object Test extends Object {
    private[this] val a: Int = _;
    <stable> <accessor> def a(): Int = Test.this.a;
    def <init>(): Test.type = {
        Test.super.<init>();
        Test.this.a = 2;  //在初始化时才对成员赋值
        ()
    }
  }
}

在对多个变量赋值,或变量中有@符合,导致模式匹配还好理解,但”2=2″也引起模式匹配就会让我产生疑问:
是否所有的赋值语句都是模式匹配?

为了验证,通过编译选项查看val a=2 这样对单个变量的赋值却没有看到模式匹配。
另外,如果单个变量也是模式匹配,为何大写字母val A=2没问题?假设对单个变量赋值也是模式匹配,那岂不无法定义大写的变量了;肯定是有区别的,但又怎么区分的?

我最初遇到这个困惑,在邮件列表里问了这个问题,得到了一些回复,并且有人给了一个老帖子链接说早就讨论过val 1=2这个话题了:http://thread.gmane.org/gmane.comp.lang.scala.user/44036

在那个帖子里,martin也回复了为何 val 1=2是模式匹配,并且为何不把这种情况作为错误给修复掉:

A value definition is of the form

val <pattern> = <expression> // 这个同ML和Erlang语言
1 is a <pattern>

There is one edge case:
If the pattern is a single variable (upper or lower case or backquoted), then it is always treated as a variable, not a constant. Otherwise, there would be no way to define such a value.

只有一种边缘情况:如果模式是一个单独的变量(大写、小写、或用反引号引起来的),那么它总被当作变量,而非常量。否则就没法定义这样的一个值。

所以1=2, "a"="b" 这样的赋值语句虽然是一个变量,但变量名称不符合上面的约束,产生了模式匹配。至于为何不修复这个问题(直接在编译时报错),也可以从这个帖子的线索中找到原因。

话说模式匹配(3) 模式匹配的核心功能是解构

http://www.artima.com/scalazine/articles/pattern_matching.html
这篇文章是odersky谈scala中的模式匹配的一段对话,我做了部分片段翻译(不是连贯的):

模式可以嵌套,就像表达式嵌套,你可以定义深层的模式,通常一个模式看起来就像一个表达式。它基本上就是同一类事情。
它看起来像一个复杂的对象树构造表达式,只是漏掉了new关键字。事实上在scala当你构造一个对象,你不需要new关键字
然后你可以在一些地方用变量做站位符替代对象树上实际的东西。

本质上,当你需要通过外部来构造对象图,模式匹配是必要的,因为你不能对这些对象添加方法
有很多场景的例子,XML是一个,所有解析过的数据落入不同的分类。
举例,一个标准的场合是当你用编译器解析抽象语法树的时候模式匹配是必要的。 阅读全文

话说模式匹配(2) scala里是怎么实现的?

在这篇martin和另外两位模式匹配领域专家的论文里说了模式匹配的几种实现方式,以及scala是选择哪种方式来实现的。
http://lampwww.epfl.ch/~emir/written/MatchingObjectsWithPatterns-TR.pdf
我引用了里面的一些描述。

在面向对象的程序中数据被组织为一级一级的类(class)
面向对象语言在模式匹配方面的问题在于如何从外部探测这个层级。

有6种实现模式匹配的方法:
1) 面向对象的分解 (decomposition)
2) 访问器模式 (visitor)
3) 类型测试/类型造型 (type-test/type-cast)
4) typecase
5) 样本类 (case class)
6) 抽取器 (extractor) 阅读全文

话说模式匹配(1) 什么是模式?

一些刚从java转到scala的同学在开发的过程中犹如深陷沼泽,因为很多的概念或风格不确定,scala里有很多的坑,模式匹配也算一个。我整理了一下自己所理解的概念,以及一些例子。这个系列最好有些scala的基本经验,或者接触过一些其他函数式语言。

要理解模式匹配(pattern-matching),先把这两个单词拆开,先理解什么是模式(pattern),这里所的模式并不是设计模式里的模式。
而是数据结构上的,这个模式用于描述一个结构的组成。

我们很容易联想到“正则表达”里的模式,不错,这个pattern和正则里的pattern相似,不过适用范围更广,可以针对各种类型的数据结构,不像正则表达只是针对字符串。

阅读全文

如何创建并运行java线程

原文链接  译者:章筱虎  校对:方腾飞

Java线程类也是一个object类,它的实例都继承自java.lang.Thread或其子类。 可以用如下方式用java中创建一个线程:

[code lang=”java”]
Tread thread = new Thread();
[/code]

执行该线程可以调用该线程的start()方法:

[code lang=”java”]
thread.start();
[/code]

阅读全文

Java并发性和多线程介绍目录

concurrency

原文地址   译文地址  译者:张坤等

  1. Java并发性和多线程介绍
  2. 多线程的优点
  3. 多线程的代价
  4. 并发编程模型
  5. 如何创建并运行java线程
  6. 竞态条件与临界区
  7. 线程安全与共享资源
  8. 线程安全及不可变性
  9. Java内存模型
  10. JAVA同步块
  11. 线程通信
  12. Java ThreadLocal
  13. Thread Signaling (未翻译)
  14. 死锁
  15. 避免死锁
  16. 饥饿和公平
  17. 嵌套管程锁死
  18. Slipped Conditions
  19. Java中的锁
  20. Java中的读/写锁
  21. 重入锁死
  22. 信号量
  23. 阻塞队列
  24. 线程池
  25. CAS
  26. 剖析同步器
  27. 无阻塞算法
  28. 阿姆达尔定律

解析Disruptor的依赖关系

原文地址:http://ifeve.com/dissecting-disruptor-wiring-up/

作者:Trisha   译者:廖涵  校对:方腾飞

现在我已经讲了 RingBuffer​ 本身,如何从它 读取​ 以及如何向它 写入​。从逻辑上来说,下一件要做的事情就是把所有的东西拼装到在一起。

我前面提到过多生产者的情况——他们通过 ProducerBarrier 保证写入操作顺序与可控。我也提到过简单场景下的多消费者数据访问。更多的消费者的场景会变得更加复杂,我们​ 实现了一些聪明的机制允许多个消费者在访问 Ring Buffer 的时候互相等待(依赖)。像很多应用里,有一连串的工作需要在实际执行业务逻辑之前完成 (happen before) —— 例如,在做任何操作之前,我们都必须先保证消息写入磁盘。

Disruptor 论文​ 和性能测试里包含了你可能想到的一些基本结构。我准备讲一下其中最有趣的那个,这多半是因为我需要练习如何使用画图板。 阅读全文

饥饿和公平

原文地址  By Jakob Jenkov  翻译 Simon-SZ  校对:方腾飞

如果一个线程因为CPU时间全部被其他线程抢走而得不到CPU运行时间,这种状态被称之为“饥饿”。而该线程被“饥饿致死”正是因为它得不到CPU运行时间的机会。解决饥饿的方案被称之为“公平性” – 即所有线程均能公平地获得运行机会。

 下面是本文讨论的主题:

1. Java中导致饥饿的原因:

  • 高优先级线程吞噬所有的低优先级线程的CPU时间。
  • 线程被永久堵塞在一个等待进入同步块的状态。
  • 线程在等待一个本身也处于永久等待完成的对象(比如调用这个对象的wait方法)。

2. 在Java中实现公平性方案,需要:

  • 使用锁,而不是同步块。
  • 公平锁。
  • 注意性能方面。 阅读全文

dissecting-disruptor-wiring-up

原文地址:http://mechanitis.blogspot.com/2011/07/dissecting-disruptor-wiring-up.html (因被墙移到墙内)

So now I’ve covered the ring buffer itself, reading from it and writing to it.

Logically the next thing to do is to wire everything up together.

I talked about multiple producers – they have the producer barrier to keep them in order and under control.  I’ve talked about consumers in a simple situation.  Multiple consumers can get a little more involved.  We’ve done some clever stuff to allow the consumers to be dependent on each other and the ring buffer.  Like a lot of applications, we have a pipeline of things that need to happen before we can actually get on with the business logic – for example, we need to make sure the messages have been journalled to disk before we can do anything. 阅读全文

深入理解Java内存模型(七)——总结

处理器内存模型

顺序一致性内存模型是一个理论参考模型,JMM和处理器内存模型在设计时通常会把顺序一致性内存模型作为参照。JMM和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照顺序一致性模型来实现处理器和JMM,那么很多的处理器和编译器优化都要被禁止,这对执行性能将会有很大的影响。

根据对不同类型读/写操作组合的执行顺序的放松,可以把常见处理器的内存模型划分为下面几种类型:

  1. 放松程序中写-读操作的顺序,由此产生了total store ordering内存模型(简称为TSO)。
  2. 在前面1的基础上,继续放松程序中写-写操作的顺序,由此产生了partial store order 内存模型(简称为PSO)。
  3. 在前面1和2的基础上,继续放松程序中读-写和读-读操作的顺序,由此产生了relaxed memory order内存模型(简称为RMO)和PowerPC内存模型。 阅读全文

可见性问题实例

说到并发安全时,我们常提及可见性的问题,通俗点讲就是线程1看不到线程2写入变量v的值(更专业的解释以及是什么导致可见性问题,又该如何解决,见扩展阅读),但一直偏于理论,实际中有没有因可见性而导致问题的例子呢?回答是肯定的,接下来我们一起来看几个例子。

这个例子很简单,新建的线程里有一个普通变量stop,用来表示是否结束循环里的自增操作。主线程启动这个线程后,将该变量置为true,观察线程是否打印出finish loop那行,如果存在可见性问题,主线程修改stop值为true,线程v看stop的值应该还是false。

[code lang=”java”]
class VisibilityThread extends Thread {
private boolean stop;

public void run() {
int i = 0;
System.out.println("start loop.");
while(!getStop()) {
i++;
}
System.out.println("finish loop,i=" + i);
}

public void stopIt() {
stop = true;
}

public boolean getStop(){
return stop;
}
}

public class VisibilityTest {
public static void main(String[] args) throws Exception {
VisibilityThread v = new VisibilityThread();
v.start();

Thread.sleep(1000);//停顿1秒等待新启线程执行
System.out.println("即将置stop值为true");
v.stopIt();
Thread.sleep(1000);
System.out.println("finish main");
System.out.println("main中通过getStop获取的stop值:" + v.getStop());
}
}
[/code]

阅读全文

return top