共计 955 个字符,预计需要花费 3 分钟才能阅读完成。
本案例来源于 java zone 社区,由于源代码里面存在一些自己开发的注解,我暂时没找到相关的文档,所以我做了一些修改。用的都是 java SDK 的 API。
关于概念:
- 原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
- 线程安全:就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
- 线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据
进入正题,如果可以从多个线程调用所有方法而没有外部同步,则类是线程安全的。为了实现这一点,线程安全方法必须是原子的,例如,其他线程只能看到方法之前或之后调用之间的状态。以下示例说明了为什么线程安全方法必须是原子的:
public class TR extends FanLibrary { | |
private volatile int i = 0; | |
public void ss() {sleep(100);// 为了更容易出现效果 | |
i++; | |
} | |
@Before | |
public void be() {output("before"); | |
} | |
@Test | |
public void sdfa() throws InterruptedException {Thread first = new Thread(() -> {ss(); | |
}); | |
Thread second = new Thread(() -> {ss(); | |
}); | |
first.start(); | |
second.start(); | |
first.join(); | |
second.join(); | |
output(i); } | |
@After | |
public void ds() {output("after"); | |
} | |
} |
控制台输出,以下内容可能会出现,代码中 sleep(100) 的原因:
INFO-> before | |
INFO-> 1 | |
INFO-> after |
其中“i++;”相当于“i = i + 1;”包含了“i + 1”和“i =”两个过程,不属于原子操作,所以在多线程访问该方法的时候是不安全的
当两个线程同时获取到 i = 0 的值时,如果此时都没有执行到“i =”这个步骤的时候,那么两个线程等号右边都是 1,然后前后执行“i = 1”这个操作,相当于 i 最终被两次赋值为 1,所以最终“i = 1”
欢迎有兴趣的童鞋一起交流
正文完