并发编程反模式

不连贯的同步性:

为了同步某个对象或者对象本身的某个域的访问,使用同步锁(内部锁或者显式锁,例如,对象本身的内部锁)来保护同步对象.但是如果访问该同步对象没有一贯性地通过同步锁获得访问,就意味着同步策略没有一贯地执行.通俗地讲就是在访问同步对象的时候,采用了双重标准,既有同步的操作也有非同步的操作,破坏了同步的连贯性和完整性.

直接调用Thread.run

直接调用Thread的run方法几乎总是个错误,应该调用Thread.start

未释放的显式锁

不同于内部锁,显式锁在控制退出了它们被请求的访问的时候,不会自动地释放.标准的技巧是由final块中释放锁;否则如果产生异常,锁仍会保存未释放状态.

Java代码

try{

}finally{

//release lock

}

空synchronized块

空的synchronized块在java存储模型下是有语义的,也是会被执行的.无论开发者试图去解决什么问题,通常会有更好的解决方案.

双重检查

在惰性初始化时候,双重检查作为降低同步开销的技巧是有缺陷的.涉及的问题是当读取一个共享可变域的时候,缺乏适当的同步.

双重检查产生的原因是早期jvm缓慢的无竞争同步和缓慢的jvm启动.

双重检查的运作方式是:首先检查在没有同步的情况下,能够被多个线程共享的resource是否被初始化,如果resource不为null就使用它,否则进入初始化的同步块,并再次检查resource是否为null.需要初始化.以便确保只有唯一的线程或者唯一的一次真正地初始化了多个线程共享的resource.通常的代码路径是:获取一个已经构建的resource的引用,并没有用到同步.这就是问题所在,当前线程可能看到一个部分创建的resource.

双重检查的真正问题在于:基于这样的一种假设:当没有使用同步时读取一个共享变量,可能发生的最坏的事情不过是错误地看到过期值(具体而言是null);在这种情况下,通过获取锁后再次检查一次,希望能避免之前看到过期值的风险.但是糟糕的情况是获取到对象的过期值是有效的(具体而言是非空),而当前对象的状态是无效或者错误的(例如是null).这样就会认为对象已经创建成功,而得到一个实际上无效,错误或者为null的resource引用.

Java代码

Java5.0以后,如果把resource声明为volatile类型,双重检查方式就能够很好地工作,因为读取未经缓存过的resource引用.另外jvm做到读取volatile变量相比读取非volatile变量的性能开销并没有增加很多,因此这种方法的性能开销也很低.另外早期jvm缓慢的无竞争同步和缓慢的jvm启动的问题现在已经解决,这种优化的效果也越发不明显.

另外为了确保初始化的安全性,可以通过创建不可变的安全对象在没有同步的状态下,可以被安全地跨线程共享,而不用关心它们是何时发布的.

Java代码


一个正确创建的对象,任何可以通过final域访问到的对象或者对象中的域,对看到它的线程都是实时,可见的.另外对于含有final域的对象,final域的初始化安全性可以抑制重排序,否则这些重排序会发生在对象的构造期间以及内部加载对象引用的时刻.

final域的对象只有在对象构造函数完成时才是可见的,对于非final域的对象,或者创建完成后可能改变的值,必须使用同步策略来确保其可见性.

下面的代码是构造安全的,虽然states是使用非线程安全的hashmap,但是在构造器中仍然是安全的,因为states是final域的,并且构造器中的代码是没有重排序,串行执行的.states的引用直到构造器完成之后才对其他线程可见.

Java代码


由构造函数中启动线程

由构造函数中启动线程,会引入子类化问题的风险,同时还会引起this引用由构造函数中发布溢出.

通知错误

notify和notifyAll方法预示着,一个对象的状态可能已经以某种方式发生改变,进而通知那些等待与相关对象关联的条件队列的线程解除堵塞,重新获取条件. 因此只有在与条件队列关联的状态发生改变后才应该去调用这些方法.否则在没有修改任何状态的情形下调用这些方法,通常是一种错误.

条件等待错误

在一个队列中等待时,Object.wait和Condition.wait不仅应该在持有正确的锁的情况下,在循环中被调用,而且要在测试过一系列谓词之后.在不持有锁,不在循环中或者没有测试某些状态的情形下调用Object.wait和Condition.wait,通常是一种错误.

休眠或者等待的时候持有锁

调用Thread.sleep的时持有锁,会导致其他的线程在很长的一段时间内无法执行,因此这是一个潜在的严重的活跃度危险.调用Object.wait和Condition.wait时持有锁也会导致同样的问题.

自旋循环

如果代码除了循环检查(忙等待)一个域是否有期望值之外,不做任何事情,就会浪费cpu时间,并且如果域不是volatile类型的,就无法保证循环检查可以终止,因为可能会持有一个过期的状态.如果等待一个状态装换的发生,采用闭锁或者条件等待通常是更好的技术

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容