多线程学习之解决线程同步的实现方法

news2024/11/17 4:30:34

 一、卖票的多线程实现

需求:共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票

代码实现:

/**
 * @Author:kkoneone11
 * @name:SellTicket1
 * @Date:2023/8/26 11:32
 */
public class SellTicket1 implements Runnable{

    private int tickets = 100;

    @Override
    public void run() {
        while(true){
            if(tickets < 0){
                break;
            }else {
                try{
                    Thread.sleep(100);
                }catch (Exception e){
                    e.printStackTrace();
                }
                tickets--;
                System.out.println(Thread.currentThread().getName() + "票数还剩余" + tickets);
            }
        }

    }
}



public class SellTicketDemo {
    public static void main(String[] args) {
        SellTicket1 st = new SellTicket1();

        Thread thread1 = new Thread(st, "窗口1");
        Thread thread2 = new Thread(st, "窗口2");
        Thread thread3 = new Thread(st, "窗口3");

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

可以看到这种程序写法的问题有:

  • 相同的票出现了多次

  • 出现了负数的票  

 问题产生的原因分析:这种多线程共享的是同一份数据,线程执行的随机性导致的,可能在卖票过程中丢失cpu的执行权,导致出现问题

二、解决问题的方案

要解决这个问题实际上就是让程序没有安全问题,如何实现其实就是让每次操作的时候只能有一个线程执行成功即可,那么可以实现的方案如下:

同步代码块

实现方法:

synchronized(任意对象) { 
	多条语句操作共享数据的代码 
}

优缺点:

  • 好处:解决了多线程的数据安全问题

  • 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

实例:

public class SellTicket1 implements Runnable{

    private int tickets = 100;
    private Object obj = new Object();

    @Override
    public void run() {
        while(true){
            synchronized (obj){
                //当线程进来的时候就会把这段代码锁起来
                if(tickets <= 0){
                    break;
                }else {
                    try{
                        Thread.sleep(100);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    tickets--;
                    System.out.println(Thread.currentThread().getName() + "票数还剩余" + tickets);
                }
            }
            //到此处锁就会释放了
        }

    }
}

public class SellTicketDemo {
    public static void main(String[] args) {
        SellTicket1 st = new SellTicket1();

        Thread thread1 = new Thread(st, "窗口1");
        Thread thread2 = new Thread(st, "窗口2");
        Thread thread3 = new Thread(st, "窗口3");

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

同步方法

实现方法:

锁住的对象是:this

修饰符 synchronized 返回值类型 方法名(方法参数) { 
	方法体;
}

静态同步方法

实现方法:

锁住的对象是:类名.class

修饰符 static synchronized 返回值类型 方法名(方法参数) { 
	方法体;
}

实例:

public class SellTicket1 implements Runnable{

    private static int tickets = 100;

    @Override
    public void run() {
        while(true){
            if("窗口一".equals(Thread.currentThread().getName())){
                //同步方法
                boolean b = synchronizedMthod();
                if(b){
                    break;
                }
            }else if("窗口二".equals(Thread.currentThread().getName())){
                //同步代码块
                synchronized (SellTicket1.class){
                    if(tickets == 0){
                        break;
                    }else{
                        try{
                            Thread.sleep(100);
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                        tickets--;
                        System.out.println(Thread.currentThread().getName() + "票数还剩余" + tickets);
                    }

                }
            }
        }

    }

    private static synchronized boolean synchronizedMthod(){
        if(tickets == 0){
            return true;
        }else{
            try{
                Thread.sleep(100);
            }catch (Exception e){
                e.printStackTrace();
            }
            tickets--;
            System.out.println(Thread.currentThread().getName() + "票数还剩余" + tickets);
            return false;
        }
    }
}



public class SellTicketDemo {
    public static void main(String[] args) {
        SellTicket1 st = new SellTicket1();

        Thread thread1 = new Thread(st, "窗口1");
        Thread thread2 = new Thread(st, "窗口2");
        Thread thread3 = new Thread(st, "窗口3");

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

ReentrantLock()

如果我们想可以直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock

方法名说明
void lock()获得锁
void unlock()释放锁

实例:

public class SellTicket1 implements Runnable{

    //票的数量
    private int tickets = 100;
    private Object obj = new Object();
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            //synchronized (obj){//多个线程必须使用同一把锁.
            try {
                lock.lock();
                if (tickets <= 0) {
                    //卖完了
                    break;
                } else {
                    Thread.sleep(100);
                    tickets--;
                    System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + tickets + "张票");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            // }
        }
    }
}


public class SellTicketDemo {
    public static void main(String[] args) {
        SellTicket1 st = new SellTicket1();

        Thread thread1 = new Thread(st, "窗口1");
        Thread thread2 = new Thread(st, "窗口2");
        Thread thread3 = new Thread(st, "窗口3");

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/936411.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mit s0681 lab2 Trace系统调用实现

实验一 实现一个用户级别的程序&#xff0c;功能为&#xff0c;指定系统调用后&#xff0c;跟踪程序的系统调用情况 分析实验 实验目标为实现一个程序去跟踪指定程序的系统调用。因此目标有两个 实现一个程序跟踪目标程序的系统调用 实现1&#xff0c;就需要在用户这边实…

六、Json 数据的交互处理

文章目录 一、JSON 数据的交互处理1、为什么要使用 JSON2、JSON 和 JavaScript 之间的关系3、前端操作 JSON3.1 JavaScript 对象与 JSON 字符串之间的相互转换 4、JAVA 操作 JSON4.1 Json 的解析工具&#xff08;Gson、FastJson、Jackson&#xff09;4.2 ResponseBody 注解、Re…

爬虫(bilibili热门课程记录)

什么是爬虫&#xff1f;程序蜘蛛&#xff0c;沿着互联网获取相关信息&#xff0c;收集目标信息。 一、python环境安装 1、先从Download Python | Python.org中下载最新版本的python解释器 2、再从Download PyCharm: Python IDE for Professional Developers by JetBrains中下…

关于msvcp140.dll丢失的解决方法,分享最简单详细的解决方法

今天&#xff0c;我将为大家详细介绍一种常见的问题——msvcp140.dll丢失&#xff0c;并提供四种不同的解决方法。希望通过这次分享&#xff0c;能够帮助大家解决这个问题&#xff0c;提高电脑使用效率。 首先&#xff0c;让我们来了解一下msvcp140.dll文件。msvcp140.dll是Mi…

JavaScript中的事件循环(Event Loop)

1. 概述 javaScript是单线程的&#xff0c;意味着它一次只能执行一个任务。然而&#xff0c;许多操作&#xff0c;如网络请求、定时器等&#xff0c;都会导致延迟&#xff0c;如果程序在等待这些操作完成时&#xff0c;可能会操作一个阻塞的效果&#xff0c;影响用户体验。这个…

设计模式之命令模式(Command)的C++实现

1、命令模式的提出 在软件开发过程中&#xff0c;“行为请求者”和“行为实现者”通常呈现一种“紧耦合”&#xff0c;如果行为的实现经常变化&#xff0c;则不利于代码的维护。命令模式可以将行为的请求者和行为的实现者进行解耦。具体流程是将行为请求者封装成一个对象&…

Git企业开发控制理论和实操-从入门到深入(六)|多人协作开发

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…

c语言实现堆

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、树1、树的概念2、树的相关概念3、树的表示 二、二叉树1、二叉树概念2、特殊的二叉树3、二叉树的性质4、二叉树的顺序结构5、二叉树的链式结构 三、堆(二叉树…

基于VHDL语言的汽车测速系统设计_kaic

摘 要 汽车是现代交通工具。车速是一项至关重要的指标。既影响着汽车运输的生产率,又关乎着汽车行驶有没有超速违章&#xff0c;还影响着汽车行驶时人们的人身安全。而伴随着我国国民的安全防范意识的逐步增强&#xff0c;人们也开始越来越关心因为汽车的超速而带来的极其严重…

2005-2022年全国各地级市经济增长目标约束

2005-2022年全国各地级市经济增长目标约束 1、时间&#xff1a;2005-2022年 2、来源&#xff1a;政府工作报告 3、指标&#xff1a;省份、城市、年份、经济增长目标硬约束、经济增长目标软约束 4、范围&#xff1a;地级市&#xff0c;每年具体城市数量参看下面图片 5、指标…

C语言_通过函数调用改变指针参数的指向

C语言_通过函数调用改变指针参数的指向 函数的参数为指针类型&#xff0c;对一般指针参数执行间接访问操作是允许函数修改原先的数组元素的&#xff0c;但是函数所接收到的参数是原参数的一份拷贝&#xff0c;所以函数对参数进行操作而不会影响实际的参数&#xff0c;就是说正常…

深度学习在自然语言处理中的十大应用领域

文章目录 1. 机器翻译2. 文本分类3. 命名实体识别4. 问答系统5. 文本生成6. 情感分析7. 语言生成与处理8. 信息检索与摘要9. 文本纠错与修复10. 智能对话系统总结 &#x1f389;欢迎来到AIGC人工智能专栏~深度学习在自然语言处理中的十大应用领域 ☆* o(≧▽≦)o *☆嗨~我是IT陈…

CausalEGM:通过编码生成建模的通用因果推理框架

英文题目&#xff1a;CausalEGM: a general causal inference framework by encoding generative modeling 中文题目&#xff1a;CausalEGM&#xff1a;通过编码生成建模的通用因果推理框架 单位&#xff1a;斯坦福大学统计系 时间&#xff1a;2023 论文链接&#xff1a;ht…

聚类分析 | MATLAB实现基于AHC聚类算法可视化

聚类分析 | MATLAB实现基于AHC聚类算法可视化 目录 聚类分析 | MATLAB实现基于AHC聚类算法可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 AHC聚类算法&#xff0c;聚类结果可视化&#xff0c;MATLAB程序。 Agglomerative Hierarchical Clustering&#xff08;自底…

Git企业开发控制理论和实操-从入门到深入(七)|企业级开发模型

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…

数据结构】二叉树篇|超清晰图解和详解:后序篇

博主简介&#xff1a;努力学习的22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a; 是瑶瑶子啦每日一言&#x1f33c;: 你不能要求一片海洋&#xff0c;没有风暴&#xff0c;那不是海洋&#xff0c;是泥塘——毕淑敏 目录 一、核心二、题目 一、核心 我们清楚…

UML四大关系

文章目录 引言UML的定义和作用UML四大关系的重要性和应用场景关联关系继承关系聚合关系组合关系 UML四大关系的进一步讨论UML四大关系的实际应用软件开发中的应用其他领域的应用 总结 引言 在软件开发中&#xff0c;统一建模语言&#xff08;Unified Modeling Language&#x…

飞桨中的李宏毅课程中的第一个项目——PM2.5的预测

所谓的激活函数&#xff0c;就是李宏毅老师讲到的sigmoid函数 和 hard sigmoid函数 &#xff0c;ReLU函数那些 现在一点点慢慢探索&#xff0c;会成为日后想都做不到的经历&#xff0c;当你啥也不会的时候&#xff0c;才是慢慢享受探索的过程。 有一说一&#xff0c;用chatGP…

观察级水下机器人使用系列之六超短基线(下)

本文主要讲述超短基线的安装校准和应用。 1、安装校准概述 水下声学导航系统标定算法的准确性很大程度上取决于所采集的数据质量、超短基线基阵的几何结构、高效的数值计算算法等方面。Mc Ewen 等在 2005 年发现了对于分立式的超短基线系统&#xff0c;水声传感器与姿态传感器…

数据结构--树4.2(二叉树)

目录 一、二叉树的定义和特点 1、定义 2、特点 二、二叉树的基本形态 1、空二叉树 2、只有一个根结点 3、根结点只有左子树 4、根结点只有右子树 5、根结点既有左子树又有右子树 6、斜树 7、满二叉树 8、满二叉树和完全二叉树 三、二叉树的性质 一、二叉树的定义和…