Thread线程二 多线程服务 卖票服务

2024-03-14 09:08

本文主要是介绍Thread线程二 多线程服务 卖票服务,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

卖票服务

引入问题:
有一百张票,分为三个从窗口

测试类

public static void main(String[] args) {RunnableImpl run=new RunnableImpl();Thread t0=new Thread(run);Thread t1=new Thread(run);Thread t2=new Thread(run);//调用start,开启多线程t0.start();t1.start();t2.start();
}

第一次代码:

只要有票就售出,三个窗口为三个线程,同时执行

public class RunnableImpl implements Runnable {
private int ticket=100;
@Override
public void run() {while (true){if(ticket>0){System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");ticket--;}}}
}

效果:
Thread-2正在卖第100张票!
Thread-2正在卖第99张票!
Thread-2正在卖第98张票!
Thread-1正在卖第100张票!
Thread-1正在卖第96张票!
Thread-2正在卖第97张票!
Thread-2正在卖第94张票!
Thread-2正在卖第93张票!
Thread-0正在卖第100张票!
原因:线程争夺资源,同时进入cpu中,系统没有调休实现,所以出现票重复 卖出的情况。

改进算法:

卖票的时间每个改为10ms,意味着线程休眠10ms。使得资源得以缓冲
static void sleep(long millis)
使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。

public class RunnableImpl implements Runnable {
private int ticket=100;
@Override
public void run() {while (true){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}if(ticket>0){System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");ticket--;}}}
}

效果:
Thread-0正在卖第100张票!
Thread-1正在卖第100张票!
Thread-2正在卖第100张票!
Thread-0正在卖第97张票!
Thread-1正在卖第97张票!
Thread-2正在卖第95张票!
原因:还是因为争夺cpu,同时进入,改进并没有找到根本原因!
在这里插入图片描述

使用synchronized(锁对象)同步代码块

synchronized(锁对象)
{可能会出现线程安全问题的代码(访问了共享数据的代码)}
注意:

  • 1.通过代码块中的锁对象,可以使用任意的对象

  • 2.但是必须保证多个线程使用的锁对象是同一个

  • 3.锁对象作用:

  • 把同步代码块锁住,只让一个线程在同步代码块中执行

      public class RunnableImpl implements Runnable {private  int ticket=100;//创建一个锁对象
    Object obj=new Object();
    @Overridepublic void run() {while (true){//同步代码块synchronized (obj)//也可以synchronized(this){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}if(ticket>0){System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");ticket--;}}}}}
    

    效果:
    Thread-0正在卖第100张票!
    Thread-0正在卖第99张票!
    Thread-0正在卖第98张票!
    Thread-0正在卖第97张票!
    Thread-0正在卖第96张票!
    Thread-0正在卖第95张票!
    Thread-0正在卖第94张票!
    Thread-0正在卖第93张票!
    原理:
    在这里插入图片描述

使用同步方法

锁对象是this
使用步骤:
1.把访问了共享数据代码抽取出来,放入到一个方法中
2.在方法上添加synchronized
代码:

public class RunnableImpl implements Runnable {
private int ticket=100;
//创建一个锁对象
@Override
public void run() {while (true){//同步代码块payTicket();}}
public synchronized void payTicket()
{if(ticket>0){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");ticket--;}
}
}

效果:
Thread-0正在卖第100张票!
Thread-0正在卖第99张票!
Thread-0正在卖第98张票!
Thread-0正在卖第97张票!
Thread-0正在卖第96张票!
Thread-0正在卖第95张票!
Thread-0正在卖第94张票!
Thread-0正在卖第93张票!
设置票为私有静态,则同步方法也是静态方法
静态的同步方法
锁对象是静态方法的锁对象是本类的class属性–>class文件对象(反射

代码:

public class RunnableImpl implements Runnable {
private static int ticket=100;//创建一个锁对象
@Override
public void run() {while (true){//同步代码块payTicket();}}
/*使用静态方法解决同步问题*/
public static synchronized void payTicket()
{//去掉synchronized 关键字换上//synchronized(RunnableImpl.class){}if(ticket>0){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");ticket--;}
}
}

这篇关于Thread线程二 多线程服务 卖票服务的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/807920

相关文章

Spring LDAP目录服务的使用示例

《SpringLDAP目录服务的使用示例》本文主要介绍了SpringLDAP目录服务的使用示例... 目录引言一、Spring LDAP基础二、LdapTemplate详解三、LDAP对象映射四、基本LDAP操作4.1 查询操作4.2 添加操作4.3 修改操作4.4 删除操作五、认证与授权六、高级特性与最佳

Spring Boot3虚拟线程的使用步骤详解

《SpringBoot3虚拟线程的使用步骤详解》虚拟线程是Java19中引入的一个新特性,旨在通过简化线程管理来提升应用程序的并发性能,:本文主要介绍SpringBoot3虚拟线程的使用步骤,... 目录问题根源分析解决方案验证验证实验实验1:未启用keep-alive实验2:启用keep-alive扩展建

Linux上设置Ollama服务配置(常用环境变量)

《Linux上设置Ollama服务配置(常用环境变量)》本文主要介绍了Linux上设置Ollama服务配置(常用环境变量),Ollama提供了多种环境变量供配置,如调试模式、模型目录等,下面就来介绍一... 目录在 linux 上设置环境变量配置 OllamPOgxSRJfa手动安装安装特定版本查看日志在

SpringCloud之LoadBalancer负载均衡服务调用过程

《SpringCloud之LoadBalancer负载均衡服务调用过程》:本文主要介绍SpringCloud之LoadBalancer负载均衡服务调用过程,具有很好的参考价值,希望对大家有所帮助,... 目录前言一、LoadBalancer是什么?二、使用步骤1、启动consul2、客户端加入依赖3、以服务

Java使用多线程处理未知任务数的方案介绍

《Java使用多线程处理未知任务数的方案介绍》这篇文章主要为大家详细介绍了Java如何使用多线程实现处理未知任务数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 知道任务个数,你可以定义好线程数规则,生成线程数去跑代码说明:1.虚拟线程池:使用 Executors.newVir

Java终止正在运行的线程的三种方法

《Java终止正在运行的线程的三种方法》停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作,停止一个线程可以用Thread.stop()方法,但最好不要用它,本文给大家介绍了... 目录前言1. 停止不了的线程2. 判断线程是否停止状态3. 能停止的线程–异常法4. 在沉睡中停止5

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操

Java捕获ThreadPoolExecutor内部线程异常的四种方法

《Java捕获ThreadPoolExecutor内部线程异常的四种方法》这篇文章主要为大家详细介绍了Java捕获ThreadPoolExecutor内部线程异常的四种方法,文中的示例代码讲解详细,感... 目录方案 1方案 2方案 3方案 4结论方案 1使用 execute + try-catch 记录

Nginx配置系统服务&设置环境变量方式

《Nginx配置系统服务&设置环境变量方式》本文介绍了如何将Nginx配置为系统服务并设置环境变量,以便更方便地对Nginx进行操作,通过配置系统服务,可以使用系统命令来启动、停止或重新加载Nginx... 目录1.Nginx操作问题2.配置系统服android务3.设置环境变量总结1.Nginx操作问题

Spring Boot 中正确地在异步线程中使用 HttpServletRequest的方法

《SpringBoot中正确地在异步线程中使用HttpServletRequest的方法》文章讨论了在SpringBoot中如何在异步线程中正确使用HttpServletRequest的问题,... 目录前言一、问题的来源:为什么异步线程中无法访问 HttpServletRequest?1. 请求上下文与线