归档之于 ‘ 2013 年7月 ’
软件事务内存导论(十一)-STM的局限性
声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。
1.1 STM的局限性
STM消除了显式的同步操作,所以我们在写代码时就无需担心自己是否忘了进行同步或是否在错误的层级上进行了同步。然而STM本身也存在一些问题,比如在跨越内存栅栏失败或遭遇竞争条件时我们捕获不到任何有用的信息。我似乎可以听到你内心深处那个精明的程序员在抱怨“怎么会这样啊?”。确实,STM是有其局限性的,否则本书写到这里就应该结束了。STM只适用于写冲突非常少的应用场景,如果你的应用程序存在很多写操作竞争,那么我们就需要在STM之外寻找解决方案了。
下面让我们进一步讨论STM的局限性。STM提供了一种显式的锁无关编程模型,这种模型允许多个事务并发地运行,并且在没有发生冲突时所有事务都能毫无滞碍地运行,所以相对其他编程模型而言STM可以提供更好的并发性和线程安全方面的保障。当事务对相同对象或数据的写访问发生冲突时,只有一个事务能够顺利完成,其他事务都会被自动重做。这种重做机制延缓了写操作冲突时竞争失败的那些写者的执行,但却提升了读者和竞争操作的胜利者的执行速度。当对于相同对象的并发写操作不频繁时,其性能就不会受到太大影响。但是随着冲突的增多,程序整体性能将因此变得越来越差。
阅读全文
软件事务内存导论(十)处理写偏斜异常
声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。
处理写偏斜异常
在6.6节中,我们曾经简单讨论了写偏斜(write skew)以及Clojure STM是如何解决这个问题的。Akka同样提供了处理写偏斜问题的支持,但是需要我们配置一下才能生效。OK,一听到配置这个词可能让你觉得有些提心吊胆,但实际操作起来其实起来还是蛮简单的。下面就让我们首先了解一下Akka在不进行任何配置情况下的默认行为。
软件事务内存导论(九) 集合与事务
声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。
集合与事务
在我们努力学习这些示例的过程中,很容易就会忘记我们所要处理的值都必须是不可变的。只有实体才是可变的,而状态值则是不可变的。虽然STM已经为我们减轻了很多负担,但如果想要在维护不可变性的同时还要兼顾性能的话,对我们来说也将是一个非常严峻的挑战。
为了保证不可变性,我们采取的第一个步骤是将单纯用来保存数据的类(value classes)及其内部所有成员字段都置为final(在Scala中是val)。然后,我们需要传递地保证我们自己定义的类里面的字段所使用的类也都是不可变的。可以说,将字段和类的定义置为final这一步是整个过程的基础,这同时也是避免并发问题的第一步。
虽说不可变性可以使代码变得又好又安全,但是由于性能问题,程序员们还是不大愿意使用这一特性。其症结在于,为了维护不可变性,我们可能在数据没发生任何变动的情况下也要进行拷贝操作,而这种无谓的拷贝对性能伤害很大。为了解决这个问题,我们在3.6节中曾经讨论过持久化数据结构以及如何使用这类数据结构来减轻程序在性能方面的负担。而在持久化数据结构的实现方面,已经有很多现成的第三方库可供使用,而Scala本身也提供了这类数据结构。由于Java也有实现好的持久化数据结构可用,所以我们就无需专门为使用这个特性而去换用自己不熟悉的语言。
除了不可变性之外,我们还希望能获得一些事务运行所需要的数据结构——这些数据结构的值是不可变的,但其实体可以在托管事务中被改变。Akka提供了两种托管数据结构——TransactionalVector和TransactionalMap。这两种数据结构源自于高效的Scala数据结构,其工作原理和Java的list、map类似。下面就让我们一起来学习如何在Java和Scala中使用TransactionalMap
软件事务内存导论(八)提交和回滚事件
声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。
提交和回滚事件
Java的try-catch-finally语法结构不但使我们可以安全地处理异常,还能够在程序抛出异常时选择性地执行一些代码。同样地,我们也可以控制程序在事务成功提交之后去执行某段代码,而当事务回滚时则去执行另一段代码。StmUtils中的deferred()和compensatiing()这两个函数分别提供了上述功能。特别地,在实现事务的过程中,为保证事务能顺利完成,我们通常会加入一些带副作用的逻辑,而deferred()函数则是一个执行所有这部分逻辑的绝佳地点。
Java 7 Concurrency Cookbook – Javier Fernández González -前言
原文下载链接 作者: Javier Fernández González 译者:郑玉婷
前言
当你用计算机工作的时候,你在同时做多样事情。你可以边听音乐边写文档边读取邮件。你可以这样做的原因是你的操作系统运行并发任务。并发编程是关于基础与进程的一个 提供多任务或者程序同时运行还相互沟通来交换数据和相互同步的平台。Java是一个并发平台,在Java程序中提供很多执行并发任务的类。每个版本,Java提升了促进程序员开发并发程序的功能。这本书包含了在Java版本7的并发API中最重要和最有用的技巧,所以你可以直接在你的应用程序中使用的,以下这些:
• 基本线程管理
• 线程同步机制
• 执行者代表的线程的创建与管理
• Fork/Join框架来提高应用程序的性能
• 并发程序的数据结构
• 按照需要来调整一些并发类的默认行为
• 测试Java的并发应用程序
软件事务内存导论(七)阻塞事务
声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。
阻塞事务——有意识地等待
我们经常会遇到这样一种情况,即某事务T能否成功完成依赖于某个变量是否发生了变化,并且由于这种原因所引起的事务运行失败也可能只是暂时性的。作为对这种暂时性失败的响应,我们可能会返回一个错误码并告诉事务T等待一段时间之后再重试。然而在事务T等待期间,即使其他任务已经更改了事务T所依赖的数据,事务T也没法立即感知到并重试了。为了解决这一问题,Akka为我们提供了一个简单的工具——retry(),该函数可以先将事务进行回滚,并将事务置为阻塞状态直到该事物所依赖的引用对象发生变化或事务阻塞的时间超过了之前配置的阻塞超时为止。我本人更愿意将这一过程称为“有意识地等待”,因为这种说法听起来比“阻塞”更合适一些。下面让我们将阻塞(或有意识地等待)用于下面的两个例子当中。
非阻塞同步算法实战(一)
感谢trytocache投递本文。
前言
本文写给对ConcurrentLinkedQueue的实现和非阻塞同步算法的实现原理有一定了解,但缺少实践经验的朋友,文中包括了实战中的尝试、所走的弯路,经验和教训。
背景介绍
上个月,我被安排独自负责一个聊天系统的服务端,因为一些原因,我没使用现成的开源框架,网络那块直接使用AIO,收数据时,因为只会从channel里过来,所以不需要考虑同步问题;但是发送数据时,因为有聊天消息的转发,所以必需处理这个同步问题。AIO中,是处理完一个注册的操作后,再执行我们定义的方法,此时,如果还有数据需要写,则继续注册写操作,如果没有则不注册;提交数据时,如果当前没有注册写操作,则注册一个,否则仅提交(此时再注册则会报异常)。这样,需要同步的点就是:如何知道当前还有没有数据需要发送(因为其它线程也可以提交数据到此处),和如何知道此次提交时,有没有注册写操作。总之,要完成:有数据要发送时,必需有写操作被注册,并且只能注册一次;没有数据时,不能有写操作被注册。 阅读全文
软件事务内存导论(六)配置Akka事务
声明:本文是《Java虚拟机并发编程》的第六章,感谢华章出版社授权并发编程网站发布此文,禁止以任何形式转载此文。
配置Akka事务
默认情况下,Akka为其相关的运行参数都设定了默认值,我们可以通过代码或配置文件akka.conf来更改这些默认设置。如果想了解如何指定或修改该配置文件位置的详细信息,请参阅Akka的文档。
针对单个事务,我们可以利用TransactionFactory在程序代码中更改其设置。下面就让我们用这种方式先后在Java和Scala中更改一些设置来为你展示如何实现设置的变更。