写于:2020-01-09
一、线程安全与数据同步
当多个线程间存在共享的资源时,便会存在线程安全的问题。为了解决共享资源的安全问题,就需要解决共享资源在各个线程间的数据同步问题。
二、数据不一致
当多个线程对一个共享的数据进行操作的时候,就会出现数据不一致的问题。
1、简单案例引出线程安全问题。
案例:多个线程多一个数字进行累加,当累加到指定数量时,结束
public class SimpleThread {
public static void main(String[] args) throws InterruptedException {
final TaskRunnable taskRunnable = new TaskRunnable();
List<Thread> threads = IntStream.rangeClosed(1, 4).mapToObj(loopTimes -> {
return new Thread(taskRunnable, "T" + loopTimes);
}).collect(Collectors.toList());
threads.stream().forEach(Thread::start);
}
public static class TaskRunnable implements Runnable{
/** 共享的数据 **/
private int index = 0;
/** 结束累加的阈值 **/
private static final int max = 15000;
@Override
public void run() {
while(index <= max){
System.out.println(Thread.currentThread() +":" + (index++));
}
}
}
}
多次运行可能出现问题如下
1、某个值重复出现
2、某个值被忽略没有出现
3、总数超过了最大值
2、问题分析
index++;不是一个原子操作;他分为三个部分 a、取值 b、累加 c、赋值
真个累加操作可以分为如下几个步骤:
- 1、while 判断
- 2、index 取值
- 3、index 累加
- 4、累加值 赋值给 index
- 5、打印 index 值
某个值重复出现
两个线程,线程1和线程2。
线程 2 拿到 CPU 执行权进行操作: 1[while判断],2[index取值],3[index累加] 。然后释放了cpu执行权。
线程 1 拿到 CPU 执行权进行操作: 1[while判断],2[index取值],3[index累加],4[赋值],5[打印],此时打印结果 index =2。然后释放 cpu 执行权。
线程 2 拿到 CPU 执行权进行操作: 4[赋值],5[打印],此时打印结果 index =2,。
出现重复值打印问题。
某个值被忽略
两个线程,线程1和线程2。
线程 2 拿到 CPU 执行权进行操作:1[while判断],2[index取值],3[index累加],4[赋值]。然后释放 cpu 执行权
线程 1 拿到 CPU 执行权进行操作:1[while判断],2[index取值],3[index累加],4[赋值],5[打印],此时打印结果 index =3,然后释放 CPU 执行权。
线程 2 拿到 CPU 执行权进行操作:5[打印],此时打印结果为 3。
出现忽略问题,2的打印被忽略了。
超过最大值
两个线程,线程1和线程2。
最大值为 500.此时 index = 499。
线程 1 拿到 CPU 执行权进行操作:1[while判断],然后释放 CPU 执行权。
线程 2 拿到 CPU 执行权进行操作:1[while判断],然后释放 CPU 执行权。
线程 1 拿到 CPU 执行权进行操作:2[index取值],3[index累加],4[赋值],5[打印]。此时 index 为最大值 500.
线程 2 由于已经通过 1[while] 的判断,所以能够接着操作:2[index取值],3[index累加],4[赋值],5[打印],此时 index 超出最大值,结果为 501.
出现超过最大值问题。
三、问题总结
出现线程安全和数据不一致的问题,都是因为多个线程同时对一个共享资源同时进行操作造成的。