线程安全问题的概述与线程安全问题的代码实现

线程安全

如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
我们通过一个案例,演示线程的安全问题:
电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是“葫芦娃大战奥特曼”,本次电影的座位共100个(本场电影只能卖100张票)。
我们来模拟电影院的售票窗口,实现多个窗口同时卖“葫芦娃大战奥特曼"这场电影票(多个窗口一起卖这100张票)需要窗口,采用线程对象来模拟;需要票,Runnable接口子类来模拟

 

二、简介
1.什么是线程安全?
(1)控制多个线程对某个资源的有序访问或修改
(2)如果一个类在多线程的访问下,其状态是可以 预测的,并且不需要额外的同步,那么这个类 就是线程安全的类
2. 为什么要线程安全?
(1) 线程不安全会造成数据错误,修正数据错误是 费时费力的
(2) 线程不安全会导致程序发生一些异常行为,而 且这种行为很难查找
(3) 线程不安全的现象一般只有在并发量大时才会 出现,因此很难重现

三、 线程不安全产生原因
1.线程工作内存与主存交互
当线程操作某个共享变量时,可能的执行顺序如下:
(1)从主存复制变量到当前工作内存
(2)执行代码,改变共享变量的值
(3) 将工作内存数据同步回主存
2. 内存可见性与互斥性
(1)可见性:一个线程的执行结果可以被另一个线程 所看到
(2)互斥性:在同一时间只能有一个线程对变量的主 存进行操作

package Demo01_Sleep;

/*
    实现卖票案例
*/
public class RunnableImpl implements Runnable{
    // 定义一个多线程贡献的票源
    private int ticket = 100;
    // 设置线程任务:卖票
    @Override
    public void run() {
        // 使用死循环 让卖票操作重复执行
        while (true){
            // 先判断票是否存在
            if (ticket >= 0){
                // 使用线程睡眠提高安全问题出现的概率
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 卖票
                System.out.println("在卖"+Thread.currentThread().getName()+"线程的第:"+ticket+"张票");
                ticket--;
            }
        }
    }
}

/* 
    模拟卖票案例
    创建了3个共享线程,同时开启,对共享的票进行出售
*/
class Demo01Ticket {
    public static void main(String[] args) {
        // 创建实现类对象
        RunnableImpl runnable = new RunnableImpl();
        // 创建Thread类对象,构造方法中传递Runnable接口的实现类
        Thread thread0 = new Thread(runnable);
        Thread thread1 = new Thread(runnable);
        Thread thread2 = new Thread(runnable);
        // 调用start开启多线程
        thread0.start();
        thread1.start();
        thread2.start();
    }
}

 

package Demo01_Sleep;

public class SellTicket implements Runnable {
    private int tickets = 100;
    //在SellTicket类中重写run()方法实现卖票,代码步骤如下
    @Override
    public void run() {
        while (true) {
            if (tickets > 0) {
                System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
                tickets--;
            }
        }
    }
}
class SellTicketDemo {
    public static void main(String[] args) {
        //创建SellTicket类的对象
        SellTicket st = new SellTicket();

        //创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称
        Thread t1 = new Thread(st,"窗口1");
        Thread t2 = new Thread(st,"窗口2");
        Thread t3 = new Thread(st,"窗口3");

        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

 

posted @ 2022-07-07 21:00  zj勇敢飞,xx永相随  阅读(32)  评论(0编辑  收藏  举报