web 初始 8

在这里插入代码片
万物都有其两面性,阴阳互相调和,方成其道。
线程也属于万物之一。
是滴,多线程在令程序员无比舒适的同时,会给程序本身带来或多或少的风险。
想给出一个线程安全的确切定义是复杂的,线程安全的概念主要以下为准:如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的。
安全的自然不必多虑,问题是不安全的时候该怎么办?为啥会不安全?
代码块危险模板实例:

在这里插入代码片
public class ThreadDemo {
private static class Counter {
private long n = 0;
public void increment() {
n++;
}
public void decrement() {
n--;
}
public long value() {
return n;
}
}
public static void main(String[] args) throws InterruptedException {
final int COUNT = 1000_0000;
Counter counter = new Counter();
Thread thread = new Thread(() -> {
for (int i = 0; i < COUNT; i++) {
counter.increment();
}
}, "李四");
thread.start();
for (int i = 0; i < COUNT; i++) {
counter.decrement();
}
thread.join();
// 期望最终结果应该是 0
System.out.println(counter.value());
}
}

在这里插入代码片
三座大山:原子性,可见性和代码顺序性,共同压在线程的头上,构成了线程不稳定的原因。
原子性:正如其名,最小单位,无法被分解,每个线程最终都会拥有阻止其他线程侵扰本线程过多功能的机制,这个现象叫做同步互斥,表示操作是互相排斥的。就比如上述代码的n++,其实有三个步骤:
1. 从内存把数据读到 CPU
2. 进行数据更新
3. 把数据写回到 CPU
薛定谔式的错误:不保证原子性会给多线程带来什么问题。
如果一个线程正在对一个变量操作,中途其他线程插入进来了,如果这个操作被打断了,结果就可能是错误的,注意是可能,也就是说不敢确切判断是否有错。
可见性:用语言描述过于抽象,以教材原图作为解释:
在这里插入图片描述
为了提高效率,JVM在执行过程中,会尽可能的将数据在工作内存中执行,但这样会造成一个问题,共享变量在多线程之间不能及时看到改变,这个就是可见性问题。
最后一个,代码顺序性,意思其实就是顺序,能来看这类博客的肯定懂一些代码格式,啥格式呢,从上到下一行一行执行,这个规则只要计算机还是二进制就不会变,但是,我可以选择将步骤打乱,进饭店,我可以先喝水后点菜再买单,也可以先点菜后买单再喝水,也可以先买单后喝水再点菜,完全随心,但电脑可不会任性,它会选择最优解:如果是在单线程情况下,JVM、CPU指令集会对其进行优化,点菜买单需要调用服务员,喝水不用,所以电脑一定不会将喝水穿插在二者中间进行,因为那需要调用两次服务员,这种叫做指令重排序,那么就会产生一个疑问,最优解那不是好事么,为什么说是不安全全因素?这就要分单线程和多线程了,在顾客只有一个的时候(单线程)最优解当然没错,但如果顾客非常多(多线程),服务员就那么点,难免不能保证出些差池什么的,比如搞错每个客人点的菜,或是忘记客人有没有买单,这个时候如果指令重排序了,那肯定就是错的,肯定没人愿意花一块牛排的钱去吃一盘蔬菜,如果有,那肯定是事先不知道价格,那么事后发现问题了,不说冲突,和店家理论也是肯定的,连用这么多“肯定”是为了加强语气,增强说服力,至少我觉得可以。
最后在这里给出上文危险模板的解决实例:

在这里插入代码片
public class ThreadDemo {
private static class Counter {
private long n = 0;
public synchronized void increment() {
n++;
比特科技
 }
public synchronized void decrement() {
n--;
}
public synchronized long value() {
return n;
}
}
public static void main(String[] args) throws InterruptedException {
final int COUNT = 1000_0000;
Counter counter = new Counter();
Thread thread = new Thread(() -> {
for (int i = 0; i < COUNT; i++) {
counter.increment();
}
}, "李四");
thread.start();
for (int i = 0; i < COUNT; i++) {
counter.decrement();
}
thread.join();
// 期望最终结果应该是 0
System.out.println(counter.value());
}
}

在这里插入代码片目前正在努力自己写实例,希望能尽快。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值