首页 > 其他分享 >线程安全案例

线程安全案例

时间:2024-10-19 10:21:16浏览次数:1  
标签:tickets Thread 安全 void 案例 线程 Student new public

多窗口售票

    使用实现Runnable接口的方式实现售票

    问题1:我们加入了循环和延迟模拟现实生活售票的场景后发现
        1. 出现售卖重复的票号 【计算机中cpu的计算是具备原子性的】
        2. 出现非法的票号  【随机性导致的,cpu小小的时间片,足以执行很多次】

    上述的问题1实际上是属于线程安全的问题。
    如何判断一个程序是否存在线程安全的问题呢?
    三要素,缺一不可:
        1、是否存在多线程环境? 是
        2、是否存在共享数据/共享变量?是tickets
        3、是否存在多条语句操作着共享数据/共享变量? 是

    怎么解决?
        方案1:同步代码块
            synchronized(对象){需要同步的代码;}  这里对象要保证多个线程对象唯一的
            同步方法:锁对象是this
            同步静态方法:锁对象是当前类的class文件对象   类.class
        方案2:lock锁
使用实现Runnable接口的方式实现售票 
synchronized(对象){需要同步的代码;}  这里对象要保证多个线程对象唯一的
点击查看代码
class Window2 implements Runnable{
    int tickets = 200;
    Object obj = new Object();

    @Override
    public void run() {
        while (true){
            synchronized (obj){
                if(tickets>0){ // 1
                    try {
                        // t1
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("当前 " + Thread.currentThread().getName()+" 正在出售第 "+(tickets--)+" 张票");
                }
            }

        }
    }
}


public class SellTicketsDemo2 {
    public static void main(String[] args) {
        Window2 window2 = new Window2();

        Thread t1 = new Thread(window2, "窗口1");
        Thread t2 = new Thread(window2, "窗口2");
        Thread t3 = new Thread(window2, "窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

`同步方法的锁对象`
点击查看代码
class Window3 implements Runnable {
    static int tickets = 200;
    int i = 0;

    @Override
    public void run() {
        while (true) {
            if (i % 2 == 0) {
                synchronized (Window3.class) {//同步代码块如果同步方法是一状态的话那么synchronized(this)
                    //如果同步方法是静态的那么则需要 synchronized (Window3.class)确保线程安全
                    if (tickets > 0) { // 1
                        try {
                            // t1
                            Thread.sleep(20);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        System.out.println("当前 " + Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票");
                    }
                }
            } else {
                sell();//同步方法
            }

            i++;
        }
    }

    public synchronized static void sell() {
        if (tickets > 0) { // 1
            try {
                // t1
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("当前 " + Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票");
        }
    }


//    public synchronized void sell() {
//        if (tickets > 0) { // 1
//            try {
//                // t1
//                Thread.sleep(20);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//
//            System.out.println("当前 " + Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票");
//        }
//    }
}


public class SellTicketsDemo3 {
    public static void main(String[] args) {
        Window3 window3 = new Window3();

        Thread t1 = new Thread(window3, "窗口1");
        Thread t2 = new Thread(window3, "窗口2");
        Thread t3 = new Thread(window3, "窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

使用lock锁来解决线程安全的问题

点击查看代码

class Window4 implements Runnable {
    int tickets = 200;
    Object obj = new Object();
    ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            // 加锁
            lock.lock();
            if (tickets > 0) { // 1
                try {
                    // t1
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("当前 " + Thread.currentThread().getName() + " 正在出售第 " + (tickets--) + " 张票");
            }
            //释放锁
            lock.unlock();
        }
    }
}


public class SellTicketsDemo4 {
    public static void main(String[] args) {
        Window4 window4 = new Window4();

        Thread t1 = new Thread(window4, "窗口1");
        Thread t2 = new Thread(window4, "窗口2");
        Thread t3 = new Thread(window4, "窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

    等待唤醒机制:
        生产者
        消费者
        共享数据
        测试类

   等待唤醒机制:前提是要保证程序是线程安全的

生产者

点击查看代码
public class Product extends Thread{

    Student s;
    int i =0;

    public Product(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
//        Student s = new Student();
        while (true){
            synchronized (s){
                //作为生产者,在生产数据之前,应该先检查一下数据有没有被消费
                //如果没有被消费,就等待消费者消费
                if(s.flag){
                    //等待 锁对象调用方法等待
                    try {
                        s.wait(); // 程序走到这一步,发生阻塞,直到锁对象再次在程序中被调用了notify()方法
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }


                if(i%2==0){
                    s.setName("李刚");
                    s.setAge(18);
                }else {
                    s.setName("钱志强");
                    s.setAge(10);
                }

                // 生产完数据后,通知消费者来消费数据
                // 由锁对象来通知
                s.notify();
                s.setFlag(true);

                i++;
            }
        }
    }
}

消费者

点击查看代码
public class Consumer extends Thread{
    Student s;

    public Consumer(Student s) {
        this.s = s;
    }

    @Override
    public void run() {
//        Student s = new Student();
        while (true){
            synchronized (s){
                //消费者在消费数据之前,应该先看一看数据有没有产生【flag是否是true】
                //若没有数据产生,等待生产者生产数据
                if(!s.flag){
                    try {
                        s.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.println(s.getName()+"-"+s.getAge());

                //消费者消费完数据后,通知生产者生产数据
                s.notify();
                s.setFlag(false);
            }

        }
    }
}

共享数据

点击查看代码

public class Student {
    private String name;
    private int age;
    boolean flag = false;


    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试类

点击查看代码

public class WaitNotifyDemo1 {
    public static void main(String[] args) {
        Student s = new Student();

        //创建生产者线程对象
        Product product = new Product(s);
        //创建消费者线程对象
        Consumer consumer = new Consumer(s);

        product.start();
        consumer.start();
    }
}

标签:tickets,Thread,安全,void,案例,线程,Student,new,public
From: https://www.cnblogs.com/wangxiaojian-lina/p/18475556

相关文章

  • 网络安全学习路线+自学笔记(超详细) 自学网络安全看这一篇就够了
    一、什么是网络安全网络安全是一种综合性的概念,涵盖了保护计算机系统、网络基础设施和数据免受未经授权的访问、攻击、损害或盗窃的一系列措施和技术。经常听到的“红队”、“渗透测试”等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。作为一......
  • 最佳的10款App安全测试工具
    网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!移动互联网时代,我们的生活和工作深受App影响。伴随移动App的广泛应用,App安全日益重要。本文介绍了App开发可能用到的安全测试工具。当今,全球移动用户大约超过37亿。GooglePlay上大约有220万个App,苹果......
  • 【软件工程】一文学会数据流图画法教程(内含案例说明)
    目录前言数据流图概念优点基本组成基本图形组成(重点)箭头矩形双横线/半框形矩形圆形/圆角矩形/椭圆形(核心)数据流图(DFD)分层1、分层说明2、顶层数据流图3、中层数据流图4、底层数据流图数据流图设计原则父图-子图平衡原则数据守恒原则守恒加工原则......
  • 如何安全运行别人上传的Python代码?
    写后端的同学,有时候需要在网站上实现一个功能,让用户上传或者编写自己的Python代码。后端再运行这些代码。涉及到用户自己上传代码,我们第一个想到的问题,就是如何避免用户编写危险命令。如果用户的代码里面涉及到下面两行,在不做任何安全过滤的情况下,就会导致服务器的Home文件夹......
  • 客户案例 | Ansys与台积电和微软合作加速光子仿真
    Ansys与台积电和微软展开合作,将硅光子器件的仿真和分析速度提高10倍以上主要亮点借助使用NVIDIA图形处理单元(GPU)的MicrosoftAzure虚拟机,AnsysLumerical™FDTD3D电磁仿真的光子器件仿真速度实现了10倍提升凭借Azure云平台的可扩展性,Ansys软件提供了理想的综合平台,可应......
  • C#中跨线程调用的方法一点总结
    引言在图形用户界面(GUI)应用程序开发中,多线程编程已成为不可或缺的一部分。通过使用多线程,开发者可以在后台执行耗时任务,同时保持用户界面的响应性。然而,多线程编程也带来了复杂性,尤其是在处理用户界面(UI)控件时。由于UI控件通常不是线程安全的,直接从非UI线程访问或修改它们可能......
  • java_day17_JDBC、登录注册修改案例
    一、JDBCJDBC编写六步走:1、注册驱动,告诉java程序我们要链接什么数据库【mysql为案例】5.1.x驱动包中的驱动类路径:【com.mysql.jdbc.Driver】8.x.x驱动包中的驱动类路径:【com.mysql.cj.jdbc.Driver】2、创建与数据库的链接对象......
  • 常见网络安全设备默认口令----适合网络安全小白
    很多时候有人会遇到攻防演练的时候碰到安全设备,但是不知道安全设备的弱口令来源网络,具体网址找不到了==,如果作者看到这篇博客的话可以联系我添加声明。看到一个可以查询默认口令的网站设备默认账号默认密码深信服产品sangforsangforsangfor@2018sangfor@2019......
  • 多线程
    进程:是系统进行资源分配和调用的独立单位,每一个进程都有它自己的内存空间和系统资源。举例:IDEA,阿里云盘,wegame,steam线程:是进程中的单个顺序控制流,是一条执行路径一个进程如果只有一条执行路径,则称为单线程程序。一个进程如果有多条执行......
  • 《安全边际》卡拉曼:市场波动对我们反而有利
    如果说起Baupost这家机构,或许你没有听过它的名字,但你一定知道《安全边际》这本书。这本书的作者塞斯·卡拉曼,正是Baupost的创始人。卡拉曼有着“波士顿先知”之称,他强调安全边际,被外界称为“半仓打天下”,同时偏好寻找受挫资产。1982年,25岁的卡拉曼联合创立波士顿对冲基金......