Java 多线程(六)线程安全

什么是线程安全?

  • 当多个线程同时共享,同一个全局变量或静态变量。做写的操作时(增、删、改),可能会发生数据冲突问题,也就是线程安全问题。但是做读操作是不会发生数据冲突问题。
  • 比如说,我们现在去上厕所。就两个厕所,但是好几十人急着上厕所。然后那个厕所又没有里面锁头,你上着厕所蹲着茅坑了,别人还推开们抢你的坑位。(这样子拉屎就不安全,需要一个锁头,别人就进不来了,需要等待)

例子

  • 现在有 30 张火车票,有三个窗口同时抢火车票,请使用多线程模拟抢票效果。
/**
 * @Author : PengPeng
 * 线程 不安全 的抢票
 * 现在有 30 张火车票,有三个窗口同时抢火车票,请使用多线程模拟抢票效果。
 */
public class Test001 {

    public static void main(String[] args) {
        ThreadDemo101 threadDemo101 = new ThreadDemo101();
        Thread t1 = new Thread(threadDemo101, "窗口一");
        Thread t2 = new Thread(threadDemo101, "窗口二");
        Thread t3 = new Thread(threadDemo101, "窗口三");
        t1.start();
        t2.start();
        t3.start();
    }

}

class ThreadDemo101 implements Runnable {
    private int fare = 30;

    @Override
    public void run() {
        // 有票就一直循环卖!
        while (fare > 0) {
            sale();
        }
    }

    private void sale() {
        // 有票继续卖
        if (fare > 0) {
            fare--;
            System.out.println(Thread.currentThread().getName() + ":卖出弟 " + (30 - fare) + " 张,还剩: " + fare + "张。");
        }
    }
}
  • 执行结果
窗口二:卖出弟 2 张,还剩: 28张。
窗口二:卖出弟 4 张,还剩: 26张。
窗口二:卖出弟 5 张,还剩: 25张。
窗口一:卖出弟 2 张,还剩: 28张。
窗口三:卖出弟 3 张,还剩: 27张。
窗口三:卖出弟 8 张,还剩: 22张。
窗口三:卖出弟 9 张,还剩: 21张。
窗口三:卖出弟 10 张,还剩: 20张。
窗口一:卖出弟 7 张,还剩: 23张。
窗口二:卖出弟 6 张,还剩: 24张。
窗口一:卖出弟 12 张,还剩: 18张。
窗口三:卖出弟 11 张,还剩: 19张。
窗口一:卖出弟 14 张,还剩: 16张。
窗口二:卖出弟 13 张,还剩: 17张。
窗口一:卖出弟 16 张,还剩: 14张。
窗口三:卖出弟 15 张,还剩: 15张。
窗口一:卖出弟 18 张,还剩: 12张。
窗口二:卖出弟 17 张,还剩: 13张。
窗口一:卖出弟 20 张,还剩: 10张。
窗口三:卖出弟 19 张,还剩: 11张。
窗口一:卖出弟 22 张,还剩: 8张。
窗口二:卖出弟 21 张,还剩: 9张。
窗口一:卖出弟 24 张,还剩: 6张。
窗口三:卖出弟 23 张,还剩: 7张。
窗口一:卖出弟 26 张,还剩: 4张。
窗口二:卖出弟 25 张,还剩: 5张。
窗口一:卖出弟 28 张,还剩: 2张。
窗口三:卖出弟 27 张,还剩: 3张。
窗口一:卖出弟 30 张,还剩: 0张。
窗口二:卖出弟 29 张,还剩: 1张。

Process finished with exit code 0

在这里插入图片描述

  • 很明显上面的代码出现了线程安全问题,有的票被多次卖出。

线程安全解决办法:

  • 如何解决多线程之间线程安全问题
    使用 synchronized 关键字或使用 lock 锁。

  • 为什么使用 synchronized 关键字或使用 lock 锁 就能解决线程安全问题呢?
    将可能会发生数据冲突问题(线程不安全问题),只能让当前一个线程进行执行。代码执行完成后释放锁,让后才能让其他线程进行执行。这样的话就可以解决线程不安全问题。

  • 什么是多线程之间同步
    当多个线程共享同一个资源,不会受到其他线程的干扰。

解决上述线程不安全的代码

  • 加入 synchronized 关键字
/**
 * @Author : PengPeng
 * 线程 安全 的抢票
 * 现在有 30 张火车票,有三个窗口同时抢火车票,请使用多线程模拟抢票效果。
 */
public class Test002 {

    public static void main(String[] args) {
        ThreadDemo102 ThreadDemo102 = new ThreadDemo102();
        Thread t1 = new Thread(ThreadDemo102, "窗口四");
        Thread t2 = new Thread(ThreadDemo102, "窗口五");
        Thread t3 = new Thread(ThreadDemo102, "窗口六");
        t1.start();
        t2.start();
        t3.start();
    }

}

class ThreadDemo102 implements Runnable {
    private int fare = 30;

    @Override
    public void run() {
        // 有票就一直循环卖!
        while (fare > 0) {
            sale();
        }
    }

    private synchronized void sale() {
        // 有票继续卖
        if (fare > 0) {
            fare--;
            System.out.println(Thread.currentThread().getName() + ":卖出了" + (30 - fare) + "张,还剩:" + fare + "张。");
        }
    }
}
窗口四:卖出了1张,还剩:29张。
窗口四:卖出了2张,还剩:28张。
窗口四:卖出了3张,还剩:27张。
窗口四:卖出了4张,还剩:26张。
窗口六:卖出了5张,还剩:25张。
窗口六:卖出了6张,还剩:24张。
窗口六:卖出了7张,还剩:23张。
窗口六:卖出了8张,还剩:22张。
窗口六:卖出了9张,还剩:21张。
窗口六:卖出了10张,还剩:20张。
窗口六:卖出了11张,还剩:19张。
窗口六:卖出了12张,还剩:18张。
窗口六:卖出了13张,还剩:17张。
窗口六:卖出了14张,还剩:16张。
窗口六:卖出了15张,还剩:15张。
窗口六:卖出了16张,还剩:14张。
窗口六:卖出了17张,还剩:13张。
窗口六:卖出了18张,还剩:12张。
窗口六:卖出了19张,还剩:11张。
窗口六:卖出了20张,还剩:10张。
窗口六:卖出了21张,还剩:9张。
窗口六:卖出了22张,还剩:8张。
窗口六:卖出了23张,还剩:7张。
窗口六:卖出了24张,还剩:6张。
窗口六:卖出了25张,还剩:5张。
窗口六:卖出了26张,还剩:4张。
窗口六:卖出了27张,还剩:3张。
窗口六:卖出了28张,还剩:2张。
窗口六:卖出了29张,还剩:1张。
窗口六:卖出了30张,还剩:0张。

Process finished with exit code 0
  • 自己测试时建议票数改大点,可以更好的看到效果。
END…
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值