好文推荐 ’ 目录归档

Fork/Join框架(六)取消任务

声明:本文是《 Java 7 Concurrency Cookbook 》的第五章,作者: Javier Fernández González     译者:许巧辉 校对:方腾飞

取消任务

当你在一个ForkJoinPool类中执行ForkJoinTask对象,在它们开始执行之前,你可以取消执行它们。ForkJoinTask类提供cancel()方法用于这个目的。当你想要取消一个任务时,有一些点你必须考虑一下,这些点如下:

  • ForkJoinPool类并没有提供任何方法来取消正在池中运行或等待的所有任务。
  • 当你取消一个任务时,你不能取消一个已经执行的任务。

在这个指南中,你将实现取消ForkJoinTask对象的例子。你将查找数在数组中的位置。第一个找到这个数的任务将取消剩下的任务(未找到这个数的任务)。由于Fork/Join框架并没有提供这种功能,所以,你将实现一个辅助类来做这个取消功能。
阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: Fork/Join框架(六)取消任务


讨喜的隔离可变性(四)收发消息

声明:本文是《Java虚拟机并发编程》的第五章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

我们可以向角色发送任何类型的消息——String、Integer、Long、Double、List、Map、元组(tuples)、Scala的case类…但其中有一点需要注意的是,上述所有类型的消息都必须是不可变的。在上述这些类型中,我对于元组有着特殊的偏好,这并非因为我听到别人把元组误读成“two-ples”时感到很有趣,而是由于元组是轻量的、不可变的并且是最容易创建的实例之一。例如,在Scala中,我们可以简单地用(number1,number2)来创建一个含有两个数字的元组。除了元组之外,Scala的case类也是用来定义消息的理想类型——因为case类是不可变的、可以进行模式匹配并且还很容易进行复制。在Java中,我们可以通过将消息定义为一个不可修改(unmodifiable)的Collection的方式来将多个对象塞到一个消息中。当我们向角色传递消息时,如果发送者和接收者都在同一个JVM里[1],则默认情况下我们传递的是消息的引用。需要注意的是,保证所传递消息的不可变性是程序员自己的责任,尤其是当所发送的消息是我们自定义的类时则更需要加倍小心。为了解决这个问题,我们可以让Akka替我们先将消息序列化,然后将序列化出来的拷贝而不是原对象的引用发送出去,这样就可以避免由于类定义不严谨所造成的问题。 阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 讨喜的隔离可变性(四)收发消息


软件事务内存导论(十)处理写偏斜异常

声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

处理写偏斜异常

在6.6节中,我们曾经简单讨论了写偏斜(write skew)以及Clojure STM是如何解决这个问题的。Akka同样提供了处理写偏斜问题的支持,但是需要我们配置一下才能生效。OK,一听到配置这个词可能让你觉得有些提心吊胆,但实际操作起来其实起来还是蛮简单的。下面就让我们首先了解一下Akka在不进行任何配置情况下的默认行为。

阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 软件事务内存导论(十)处理写偏斜异常


软件事务内存导论(八)提交和回滚事件

声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

提交和回滚事件

Java的try-catch-finally语法结构不但使我们可以安全地处理异常,还能够在程序抛出异常时选择性地执行一些代码。同样地,我们也可以控制程序在事务成功提交之后去执行某段代码,而当事务回滚时则去执行另一段代码。StmUtils中的deferred()和compensatiing()这两个函数分别提供了上述功能。特别地,在实现事务的过程中,为保证事务能顺利完成,我们通常会加入一些带副作用的逻辑,而deferred()函数则是一个执行所有这部分逻辑的绝佳地点。

阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 软件事务内存导论(八)提交和回滚事件


软件事务内存导论(七)阻塞事务

声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

阻塞事务——有意识地等待

我们经常会遇到这样一种情况,即某事务T能否成功完成依赖于某个变量是否发生了变化,并且由于这种原因所引起的事务运行失败也可能只是暂时性的。作为对这种暂时性失败的响应,我们可能会返回一个错误码并告诉事务T等待一段时间之后再重试。然而在事务T等待期间,即使其他任务已经更改了事务T所依赖的数据,事务T也没法立即感知到并重试了。为了解决这一问题,Akka为我们提供了一个简单的工具——retry(),该函数可以先将事务进行回滚,并将事务置为阻塞状态直到该事物所依赖的引用对象发生变化或事务阻塞的时间超过了之前配置的阻塞超时为止。我本人更愿意将这一过程称为“有意识地等待”,因为这种说法听起来比“阻塞”更合适一些。下面让我们将阻塞(或有意识地等待)用于下面的两个例子当中。

阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 软件事务内存导论(七)阻塞事务


软件事务内存导论(六)配置Akka事务

声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

配置Akka事务

默认情况下,Akka为其相关的运行参数都设定了默认值,我们可以通过代码或配置文件akka.conf来更改这些默认设置。如果想了解如何指定或修改该配置文件位置的详细信息,请参阅Akka的文档。

针对单个事务,我们可以利用TransactionFactory在程序代码中更改其设置。下面就让我们用这种方式先后在Java和Scala中更改一些设置来为你展示如何实现设置的变更。

阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 软件事务内存导论(六)配置Akka事务


软件事务内存导论(四)创建事务

声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

创建事务

我们创建事务的目的是为了协调针对多个托管引用的变更。事务将会保证这些变更是原子的,也就是说,所有的托管引用要么全部被提交要么全部被丢弃,所以在事务之外我们将不会看到有任何局部变更(partial changes)出现。此外,我们也可以用创建事务的方式来解决对单个ref先读后写所引发的相关问题。

Akka是用Scala开发出来的,所以如果我们工作中用的是Scala的话,就可以直接幸福地享用Akka简洁明了的API了。对于那些日常工作中不能使用Scala开发的程序员,Akka同样也提供了一组方便的API,以帮助他们通过Java语言来使用该类库的功能。本节我们将会看到如何利用Akka在Java和Scala中创建事务。

首先我们需要选一个适合用事务来解决的例子。我们在第5章中重构的EnergySource类使用了显式的加锁和解锁操作(其最终版本详见5.7节),下面让就我们将这些显式的加锁/解锁操作换用Akka的事务API来实现。

阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 软件事务内存导论(四)创建事务


软件事务内存导论(二)软件事务内存

声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

1.1    软件事务内存

将实体与状态分离的做法有助于STM(软件事务内存)解决与同步相关的两大主要问题:跨越内存栅栏和避免竞争条件。让我们先来看一下在Clojure上下文中的STM是什么样子,然后再在Java里面使用它。

通过将对内存的访问封装在事务(transactions)中,Clojure消除了内存同步过程中我们易犯的那些错误(见《Programming Clojure》[Hal09]和《The Joy of Clojure》[FH11])。Clojure会敏锐地观察和协调线程的所有活动。如果没有任何冲突——例如,每个线程都在存取不同账户——则整个过程中就不会涉及到任何锁,于是也就不会有延迟,并最终达到最大的并发度。当有两个线程试图访问相同数据时,事务管理器就会介入解决冲突,而我们的代码也就无需涉及任何显式加锁的操作。下面让我们一起研究一下这套系统是如何运作的。

在设计上,值(values)是不可变的,而实体(identities)也仅在Clojure的事务中是可变的。在Clojure中,压根就没有改变状态的方法,也没有任何相关的编程工具可用。而如果出现任何试图在事务之外改变实体的动作时,系统就会抛出illegalStateException异常。换句话说,一旦与事务进行了绑定,在没有冲突时,所有变更都是即时生效的;而一旦发生冲突,Clojure将会自动将事务回滚并重试。我们程序员的主要职责是保证事务中的代码都是幂等的——这是我们在函数式编程中避免副作用的常用手段,而这种手段在Clojure的编程模型中也同样适用。 阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 软件事务内存导论(二)软件事务内存


软件事务内存导论(一)前言

声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。

请回忆一下你最近完成那个需要对共享可变变量进行同步的项目。在那个项目中,你肯定无法身心愉悦地享受出色地完成工作所带来的乐趣,而是会陷入无尽的质疑之中并抓狂地挨个确认是否在所有需要的地方都作了适当的同步。在过去所经历过的编程工作中,我已经遇到过好几次这样令人神经衰弱的情况了,而其中绝大部分原因都是由于我们在用Java编程的时候没有遵循正确原则和方法来处理共享可变状态。如果我们在某个该同步的地方忘了进行同步,那些不可预知的、潜在的灾难性的结果就将在不远处等待着我们。但是人无完人,遗忘是我们的天性。所以我们应该充分利用工具来弥补我们自身的不足,同时也可以让工具帮助我们实现我们充满创意的大脑所追求的那些伟大的目标,而不是让错误一次次地打击我们的信心。为了能够得到可控的行为和结果,我们需要再次把目光投向JDK。

在本章中,我们将会通过使用Clojure中十分流行的软件事务内存(STM)模型来学习如何线程安全地处理共享可变性(shared mutability)。在需要的时候,我们可能会在示例项目中混入Clojure的代码。但是我们并非强迫你也要使用Clojure,因为随着Multiverse和Akka这些优秀工具的出现,我们也可以在Java中直接使用STM了。在本章中,我们会先来看看STM在Clojure里是什么样子,然后再学习如何用Java和Scala对事务内存进行编程。这种编程模型非常适用于那些读多写少的程序——它简单易用并能提供可预测的结果。 阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 软件事务内存导论(一)前言


并发编程网站推荐

并发编程网站

  1. Thread newsgroup(很多多线程相关的问题)
  2. preshing
  3. Doug Lea workstation (并发编程大师Doug lea的个人网站)
  4. Concurrency mail list  (Doug lea搞的邮件列表)
  5. oracle dave  (oracle 并发编程小组成员)
  6. lycog.com
  7. edu papers (很多并发编程相关的论文)
  8. oracle concurrency (oracle网站)
  9. mechanical-sympathy(需要翻墙,主要分享如何利用硬件的特性来实现高性能编程)
  10. Quora concurrency (quora问答网站的并发问题讨论)
  11. stackoverflow concurrency(stackoverflow问答网站的并发问题讨论)
  12. developerworks concurrency(并发编程专题文章)
  13. tumblr concurrency (涵盖多个语言的并发相关文章)
  14. JDK concurrent(官方jdk1.6 concurrent包API中文文档)
  15. trans-memory (研究内存事务的网站)

阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 并发编程网站推荐


Java NIO系列教程(五) 通道之间的数据传输

原文地址:http://tutorials.jenkov.com/java-nio/scatter-gather.html

作者:Jakob Jenkov   译者:郭蕾     校对:周泰

在Java NIO中,如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel(译者注:channel中文常译作通道)传输到另外一个channel。

transferFrom()

FileChannel的transferFrom()方法可以将数据从源通道传输到FileChannel中(译者注:这个方法在JDK文档中的解释为将字节从给定的可读取字节通道传输到此通道的文件中)。下面是一个简单的例子:

RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
FileChannel      fromChannel = fromFile.getChannel();

RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
FileChannel      toChannel = toFile.getChannel();

long position = 0;
long count = fromChannel.size();

toChannel.transferFrom(position, count, fromChannel);

方法的输入参数position表示从position处开始向目标文件写入数据,count表示最多传输的字节数。如果源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数。
此外要注意,在SoketChannel的实现中,SocketChannel只会传输此刻准备好的数据(可能不足count字节)。因此,SocketChannel可能不会将请求的所有数据(count个字节)全部传输到FileChannel中。

transferTo()

transferTo()方法将数据从FileChannel传输到其他的channel中。下面是一个简单的例子:

RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
FileChannel      fromChannel = fromFile.getChannel();

RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
FileChannel      toChannel = toFile.getChannel();

long position = 0;
long count = fromChannel.size();

fromChannel.transferTo(position, count, toChannel);

是不是发现这个例子和前面那个例子特别相似?除了调用方法的FileChannel对象不一样外,其他的都一样。
上面所说的关于SocketChannel的问题在transferTo()方法中同样存在。SocketChannel会一直传输数据直到目标buffer被填满。

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: Java NIO系列教程(五) 通道之间的数据传输


JIT与可见性

原文地址 (被墙移到墙内)

 Overview

Many developers of multi-threaded code are familiar with the idea that different threads can have a different view of a value they are holding, this not the only reason a thread might not see a change if it is not made thread safe.  The JIT itself can play a part.

Why do different threads see different values?

When you have multiple threads, they will attempt to minimise how much they will interact e.g. by trying to access the same memory.  To do this they have a separate local copy e.g. in Level 1 cache.  This cache is usually eventually consistent.  I have seen short periods of between one micro-second and up to 10 milli-seconds where two threads see different values.  Eventually the thread is context switched, the cache cleared or updated.  There is no guarantee as to when this will happen but it is almost always much less than a second. 阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: JIT与可见性


Java HotSpot VM中的JIT编译


原文地址译者:郭蕾 校对:丁一

本文是Java HotSpot VM and just-in-time(JIT) compilation系列的第一篇。

Java HotSpot虚拟机是Oracle收购Sun时获得的,JVM和开源的OpenJDK都是以此虚拟机为基础发展的。如同其它虚拟机,HotSpot虚拟机为字节码提供了一个运行时环境。实际上,它主要会做这三件事情:

  • 执行方法所请求的指令和运算。
  • 定位、加载和验证新的类型(即类加载)。
  • 管理应用内存。

最后两点都是各自领域的大话题,所以这篇文章中只关注代码执行。

阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: Java HotSpot VM中的JIT编译


Inter Thread Latency

原文地址:http://mechanical-sympathy.blogspot.com/2011/08/inter-thread-latency.html (移到墙内)

Message rates between threads are fundamentally determined by the latency of memory exchange between CPU cores.   The minimum unit of transfer will be a cache line exchanged via shared caches or socket interconnects.  In a previous article I explained Memory Barriers and why they are important to concurrent programming between threads.  These are the instructions that cause a CPU to make memory visible to other cores in an ordered and timely manner. 阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: Inter Thread Latency


Write Combining

原文链接:http://mechanical-sympathy.blogspot.com/2011/07/write-combining.html(有墙移动到墙内)

Modern CPUs employ lots of techniques to counteract the latency cost of going to main memory. These days CPUs can process hundreds of instructions in the time it takes to read or write data to the DRAM memory banks.

The major tool used to hide this latency is multiple layers of SRAM cache. In addition, SMP systems employ message passing protocols to achieve coherence between caches. Unfortunately CPUs are now so fast that even these caches cannot keep up at times. So to further hide this latency a number of less well known buffers are used.

This article explores “write combining store buffers” and how we can write code that uses them effectively.

CPU caches are effectively unchained hash maps where each bucket is typically 64-bytes. This is known as a “cache line”. The cache line is the effective unit of memory transfer. For example, an address A in main memory would hash to map to a given cache line C.

阅读全文

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: Write Combining


return top