【JavaEE】线程安全

发布于:2022-12-26 ⋅ 阅读:(400) ⋅ 点赞:(0)

目录

案例

原因

解决方法

具体操作


案例

让我们来做个小测试,两个线程,每个线程循环1w次让num累加,共计2w次,执行完让我们看结果。

我们发现每次执行后num的数值都不一样,且不是我们想要的数值 - 20000

 

class Count {
    public int num = 0;

    public void increase() {
        num++;
    }
}
public class test {
    public static void main(String[] args) throws InterruptedException {
        Count count = new Count();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1_0000; i++) {
                count.increase();
            }
        }) ;
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1_0000; i++) {
                count.increase();
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count.num);
    }
}

原因

引起线程不安全主要分为五点:

1.抢占式执行(线程不安全的万恶之源 罪魁祸首)

【多个线程的调度执行,可以视为“全随机”的】

2.多个线程修改同一个变量

3.修改操作不是原子的 【原子:表示不可分割的最小单位】

4.内存可见性问题:JVM对代码的优化

【程序员写代码的水平有高有低,因此设计编译器的大佬们为了缩小其中的差距,会对代码进行优化,将代码的执行逻辑等价转换成另一种逻辑,使代码在逻辑不变的基础上,效率获得提升】

5.指令的重排序:也是由于JVM对代码的优化所引起的问题

解决方法

原因1是内核实现的,我们无法进行干预

原因2我们可以对代码进行调整以此来规避线程不安全,但适用性较低,相对比较麻烦

因此我们将目光聚焦到第三点:

我们可以将一系列操作打包成原子来执行,以此来规避线程不安全。

具体操作

加锁

关键字:synchronized

可以修饰方法,可以修饰代码块。

但同时我们要注意,当多个线程对同一变量进行修改操作时,每个线程执行的操作中都要对其进行加锁,如果线程没有全部加锁,那么也是徒劳的,依然会引发线程不安全的问题。

1. 当我们对方法进行加锁时:

public synchronized void increase() {
    num++;
}

 2.对想要加锁的代码进行加锁

我们这里填入this就好

public void increase() {
    synchronized (this) {
        num++;
    }
}

3.当不完全加锁时

输出的num 会重新变成随机数
因此我们都要对其进行加锁
class Count {
    public int num = 0;

    public void increase() {
        synchronized (this) {
            num++;
        }
    }
    public void add() {
        num++;
    }
}
public class test {
    public static void main(String[] args) throws InterruptedException {
        Count count = new Count();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1_0000; i++) {
                count.increase();
            }
        }) ;
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1_0000; i++) {
                count.add();
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("num: " + count.num);
    }
}

本文含有隐藏内容,请 开通VIP 后查看