Java多线程编程(五)-并发编程原理(写线程安全的Java代码)
来源:互联网 发布:软件测试资格认证 编辑:程序博客网 时间:2024/06/05 00:54
在写Java程序的时候,何时需要进行并发控制,关键在于判断这段程序或这个类是否是线程安全的。
当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步,这个类的行为仍然是正确的,那么称这个类是线程安全的。我们设计类就是要在有潜在并发问题存在情况下,设计线程安全的类。线程安全的类可以通过以下手段来满足:
满足线程安全的一些思路
1)从源头避免并发问题
很多开发者一想到有并发的可能就通过底层技术来解决问题,其实往往可以通过上层的架构设计和业务分析来避免并发场景。比如我们需要用多线程或分布式集群来计算一堆客户的相关统计值,由于客户的统计值是共享数据,因此会有并发潜在可能。但从业务上我们可以分析出客户与客户之间数据是不共享的,因此可以设计一个规则来保证一个客户的计算工作和数据访问只会被一个线程或一台工作机完成,而不是把一个客户的计算工作分配给多个线程去完成。这种规则很容易设计。当你从源头就避免了并发问题的可能,下面的工作就完全可以不用担心线程安全问题。
2)无状态就是线程安全
多线程编程或者分布式编程最忌讳有状态,一有状态就不但限制了其横向扩展能力,也是产生并发问题的起源。当你设计的类是无状态的,那么它永远都是线程安全的。因此在设计阶段需要考虑如何用无状态的类来满足你的业务需求
3)分清原子性操作和复合操作
所谓原子性,是说一个操作不会被其他线程打断,能保证其从开始到结束独享资源连续执行完这一操作。如果所有程序块都是原子性的,那么就不存在任何并发问题。而很多看上去像是原子性的操作正式并发问题高灾区。比如所熟知的计数器(count++)和check-then-act,这些都是很容易被忽视的,例如大家所常用的惰性初始化模式,以下代码就不是线程安全的:
@NotThreadSafepublic class LazyInitRace { private ExpensiveObject instance = null; public ExpensiveObject getInstance() { if (instance == null) instance = new ExpensiveObject(); return instance; }}
这段代码具体问题在于没有认识到if(instance==null)和instance = new ExpensiveObject();是两条语句,放在一起就不是原子性的,就有可能当一个线程执行完if(instance==null)后会被中断,另一个线程也去执行if(instance==null),这次两个线程都会执行后面的instance = new ExpensiveObject();这也是这个程序所不希望发生的。
虽然check-then-act从表面上看很简单,但却普遍存在与我们日常的开发中,特别是在数据库存取这一块。比如我们需要在数据库里存一个客户的统计值,当统计值不存在时初始化,当存在时就去更新。如果不把这组逻辑设计为原子性的就很有可能产生出两条这个客户的统计值。
在单机环境下处理这个问题还算容易,通过锁或者同步来把这组复合操作变为原子操作,但在分布式环境下就不适用了。一般情况下是通过在数据库端做文章,比如通过唯一性索引或者悲观锁来保障其数据一致性。当然任何方案都是有代价的,这就需要具体情况下来权衡。
另外,java1.5以后提供了一套提供原子性操作的类,有兴趣的可以研究一下它是如何在软件层面保证原子性的。
4)锁的合理使用
大家都知道可以用锁来解决并发问题,但在具体使用上还有很多讲究,比如:
- Java多线程编程(五)-并发编程原理(写线程安全的Java代码)
- 探索并发编程(二)------写线程安全的Java代码
- 探索并发编程(二)------ 写线程安全的Java代码
- 探索并发编程(二)------写线程安全的Java代码
- 探索并发编程(二)------写线程安全的Java代码
- 探索并发编程(二)------写线程安全的Java代码
- 探索并发编程(二)------写线程安全的Java代码
- JAVA并发编程(三)设计线程安全的类
- java并发编程的艺术(五)-----线程状态
- 五、Java 多线程 并发编程#
- java多线程和并发编程(一)--- java 线程小结
- Java并发编程(8):多线程环境中安全使用集合API(含代码)
- 【Java并发编程】之八:多线程环境中安全使用集合API(含代码)
- 【Java并发编程】之八:多线程环境中安全使用集合API(含代码)
- 【Java并发编程】之八:多线程环境中安全使用集合API(含代码)
- 【Java并发编程】之八:多线程环境中安全使用集合API(含代码)
- 【Java并发编程】之八:多线程环境中安全使用集合API(含代码)(r)
- 【Java并发编程】之八:多线程环境中安全使用集合API(含代码)
- mini2440的uboot-2010.03移植 《一》
- Windows下使用python虚拟环境Virtualenv
- eldk (Embeded Linux Development Kit)安装
- 快速幂
- 从稀疏表示到低秩表示http://blog.csdn.net/tiandijun/article/details/41578175
- Java多线程编程(五)-并发编程原理(写线程安全的Java代码)
- 不同OpenCV版本和不同VS版本之间配置时的注意事项
- 计算机网络提高题目
- 项目管理博文汇总
- Virtual Memory
- 获取一个路径所在存储设备的属性
- Drupal 中fonts.googleapi.com字体的处理
- VLOOKUP 返回值不能全部被显示,有些出现“值不可用"错误
- 《改变未来的九大算法》读书笔记