您的位置:首页 > 编程语言 > Java开发

阅读 JAVA并发编程实战 (一)

2015-11-09 11:32 351 查看
什么是线程安全性?安全性就是正确性。举例说明:山顶洞人围着篝火吃肉,为了公平,大家每人都咬一口,接着传给下一个人。而每个人在吃肉的时候都是他自己一个人拿着这个肉,别人是不能碰的。如此来回传递,每人每次都是只咬一口,最后剩下骨头,所以大家吃的肉都一样多。这就是安全性,其中人都是一个线程(多个人就是多个线程),肉,是大家竞争的东西,为了保证大家共同拥有,每个都得平均分配,这就是线程安全性(正确性)。

明白上边的举例之后可以给类的线程安全作出一个定义:当多个线程访问某个类时(交替访问),这个类始终都表现出正确的行为,那么就称这个类是线程安全的。那么这个正确的行为是什么呢?其实就是一种状态,就如上边例子中所描述的 “肉” 就是一种状态。“肉”这种状态是从有到无,从大到小,每一个线程都参与过,每一个线程都拿到了自己正确的结果,也就是说这个状态的变化始终是正确的。多线程的问题就可以说是多个线程对一个状态的变化保持正确的结果的行为。若是一个类没有状态的话,那么也就不存在线程安全的问题了(无状态的对象一定是线程安全的)。

名词解释:

对象的状态:是指存储在状态变量(实例或静态域)中的数据。对象的状态可能包含其他依赖对象的域(List<?>):

实例:private User user = new User();

静态域:private static int count = 0;

其他依赖对象的域:private List<User> list = new ArrayList<User>();

共享:指变量可以由多个线程同时访问;

可变:指变量的值在其生命周期内可以发生变化;

同步机制(synchronized)是一种独占的加锁方式;

一个对象是否是线程安全的,取决于它是否被多个线程访问。要使得对象是线程安全的,需要采用同步机制(synchronized)来协同对对象的可变状态的访问。当多个线程访问某个状态变量并且其中有一个线程执行写入操作,那么必须采用同步机制(synchronized)来协同这些线程对变量的访问,如上边的山顶洞人的解释。

原子操作:是不需要synchronized的操作,就是指不会被线程调度机制打断的操作,这种操作一旦开始就一直运行到结束,中间不会有任何变化(切换到另一个线程); 举例:



该类在单线程中运行是安全的,但是在多线程中运行就会发生问题,是非线程安全的。execute方法中的 ++count 它不是原子操作,实际上它包含三个独立的操作:1、读取count的值,2、将count值加1,3、将结果重新写入count。这是一个“读取 - 修改 -
写入”
的操作序列,其结果依赖于之前的状态。这三个操作每个单独拿出来就是一个原子操作。如果没有同步的情况下,多个线程同时访问该操作的时候,其中一个线程修改了count值,还未写入,而其他线程这时候却读取该值,那么我们就会得到一个错误的结果。这是由于不恰当的执行时序而出现不正确的结果的一种非常重要的情况。它有一个正式的名字:竞态条件。

读取 - 修改 - 写入:当某个计算的正确性取决于多个线程的交替执行时序时,那么就会发生竞态条件。----线程不安全

延迟初始化: 即先检查后执行。其目的是将对象的初始化推迟到实际使用时才进行,同时要确保只被初始化一次。----线程不安全



复合操作:我们把 "读取 - 修改 - 写入"和“延迟初始化”等操作称为复合操作。复合操作中包含了一组以原子方式执行的操作以确保线程安全,所以对于复合操作,我们必须加锁的方式确保线程安全。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: