线程安全问题
作者简介: zoro-1,目前大二,正在学习Java,数据结构,mysql,javaee等
作者主页: zoro-1的主页
欢迎大家点赞 ? 收藏 ⭐ 加关注哦!??
线程安全
- 举一个小李子
- count++在cpu上的指令
- 一次错误的并发执行
- 一次正确的并发执行
- 线程不安全的原因
- 线程安全问题如何解决
- 锁
- 如何上锁
举一个小李子
public class ThreadText2 {
static int count = 0;
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
Thread thread = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
count++;
}
});
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
count++;
}
});
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println(count);
}
}
我们发现上述代码执行的结果居然是14209,按理来说不应该是20000吗,那是因为这里发生了线程安全问题
count++在cpu上的指令
load:把内存中的数据加载到寄存器中
add:进行++计算
save:把寄存器的值写回内存中
一次错误的并发执行
首先执行左边的load读取count的值,然后执行右边的load读取count的值,然后右面执行add,然后右面执行save,此时内存中的count的值更新为1,然后执行左面add,然后右面执行save,count中的值还是更新为1,相当于两次++操作实则只执行了一次一样
一次正确的并发执行
执行左边的load读取count的值,然后左面执行add,然后左面执行save,此时内存中的count的值更新为1,执行右边的load读取count的值1,然后右面执行add,然后右面执行save,此时内存中的count的值更新为2,这样就完美的执行两次了
线程不安全的原因
1.根本原因:操作系统上的线程是随机调度,“抢占式执行”
2.代码结构:多个个线程修改同一个变量
3.直接原因:count++的操作不是原子性的,执行到一般可能会被调出cpu让其他线程有“可乘之机”
线程安全问题如何解决
针对原因三可以将cpu上的三个指令打包成一个整体,这里就引入了锁的概念
锁
1.特点:具有“互斥”,“排他”性
2.目的:将cpu的指令打包为一个具有原子性的操作,并非完全的原子性
3.最核心的规则:如果一个线程针对一个对象加上锁后,其他线程也尝试对这个对象加锁,就会产生阻塞(BLOCKED),一直到前一个线程释放锁为止
比如:去图书馆占座(上锁),中途想学习(被调度)还是休息(被调走)都行,期间别人不能来,走了(释放锁),比人就可以。。。。。
如何上锁
public class ThreadText2 {
static int count = 0;
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
Thread thread = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
synchronized (lock) {
count++;
}
}
});
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
synchronized (lock) {
count++;
}
}
});
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println(count);
}
}
今天的分享到这里就结束了,感谢大家支持
还没有评论,来说两句吧...