商城网站建设付款怎么实现,python做问卷调查的网站,建设部招标网站,中国十大财务软件线程安全对于我们编写多线程代码是非常重要的。
什么是线程安全#xff1f;
在我们平时的代码中有些代码在单线程程序中可以正常执行#xff0c;但如果同样的代码放在在多个线程中执行就会引发BUG#xff0c;而这种现象我们一般称为 “线程安全问题” 或 “线程不安全”。…线程安全对于我们编写多线程代码是非常重要的。
什么是线程安全
在我们平时的代码中有些代码在单线程程序中可以正常执行但如果同样的代码放在在多个线程中执行就会引发BUG而这种现象我们一般称为 “线程安全问题” 或 “线程不安全”。 例如使用两个线程对 count 变量进行自增操作每个线程10000次。
private static int count;
public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(()-{for (int i 0; i 10000; i) {count;}});Thread t2 new Thread(()-{for (int i 0; i 10000; i) {count;}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);
}结果可以看到和我们预期的并不相同而且当我们多运行几次后每次的结果还都不相同这就是一个典型的 线程安全问题 为什么会出现上述情况呢 自增操作本质上其实分为三步 – 从内存把数据读到 CPU – 进行加一操作 – 把新数据写回到 CPU 两个线程是并发执行
所以就会引发下面这种状况(程序按照时间线从上往下执行) 这里只是简单画了六种由于线程的调度是无序的所以这里会有无数种情况但是在这无数种情况中只有当两个线程的调度每次都满足前两种情况才不会发生BUG。
引发线程安全的原因
一般引发线程安全都有以下原因
操作系统中线程的调度是随机的抢占式执行罪魁祸首多个线程针对同一个变量进行修改修改操作不是原子的内存可见性问题指令重排序问题
想要解决线程安全问题就需要从上面这几点出发由于我们上述的代码不涉及4和5所以无需考虑它们而第一点是系统原因是客观存在的无法更改。
我们此时有两种解决方法
将这个代码改为单线程解决多个线程针对同一个变量进行修改的问题让该自增操作变为原子的解决修改操作不是原子的问题
这两种方法都可以解决此代码的线程安全问题第一种很好实现那么我们该怎样让这个自增操作变为原子的呢加锁
synchronized 关键字
synchronized 关键字是JAVA提供的一种常用的加锁工具。
注
synchronized关键字在使用时需要搭配()和{};程序执行进入 { 加锁 离开 } 解锁 {} 里面就是被加锁的代码块()里面用来表示一个加锁的对象这个对象是啥不重要它的主要功能就是用来区分多个线程是否在竞争同一个锁。 如果多个线程对同一个线程尝试进行加锁操作就会产生锁竞争(其中一个线程就会发生阻塞等待)如果是不同对象就不会产生锁竞争仍然是并发执行。 我们先随便创建一个Object类型的对象命名为lock将count放入{}中
private static int count;
public static void main(String[] args) throws InterruptedException {Object lock new Object();Thread t1 new Thread(()-{for (int i 0; i 10000; i) {synchronized(lock) {count;}}});Thread t2 new Thread(()-{for (int i 0; i 10000; i) {synchronized(lock) {count;}}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);
}由于我们对count加了锁所以线程t1和t2就会在执行过程中相互影响。 当t1线程在执行操作时如果t2线程也想执行操作就会发生阻塞等待当t1线程执行完操作出了 } 后会解锁此时 t2 才会继续向下执行。
此时这个程序的执行顺序就只会是这类正确的类型