【JavaEE】多线程代码案例(1)

在这里插入图片描述
🎏🎏🎏个人主页🎏🎏🎏
🎏🎏🎏JavaEE专栏🎏🎏🎏
🎏🎏🎏上一篇文章:多线程(2)🎏🎏🎏

文章目录

  • 1.单例模型
    • 1.1概念
    • 1.2如何保证只有一个对象
    • 1.3两种单例模式
    • 1.4两种模式的线程安全
      • 1.4.1饿汉模式——线程安全
      • 1.4.2懒汉模式——线程不安全
    • 2.2.阻塞队列
    • 2.1概念
    • 2.2两种队列
      • 2.2.1阻塞队列
      • 2.2.2消息队列
    • 2.3模拟实现阻塞队列

1.单例模型

1.1概念

单例模型——》单个实例,在整个进程中某一个类只有一个实例化对象(不会new出来多个对象)称为单例模型。

1.2如何保证只有一个对象

靠我们程序猿本身来保证,这样肯定是不现实的,所以需要编译器来帮我们来做一个强制的检查,通过一些编码上的技巧,使编译器可以自动发现我们的代码是否有多个对象,并且在尝试创建多个实例的时候,直接编译出错。

1.3两种单例模式

  1. 饿汉模式
    在程序开始的时候就创建了对象,之后需要用到这个对象只需要调用这个对象即可,不需要再重新创建一个对象。为了防止创建出多个对象,可以利用代码的结构来操作比如创建以一个私有的构造方法。
//1.饿汉模式
class Singleton {private static Singleton instance = new Singleton();public static  Singleton getInstance() {return instance;}private Singleton() {}
}
public class Deom22 {public static void main(String[] args) {Singleton.getInstance();Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s1 == s2);}
}
  1. 懒汉模式
    相比饿汉模式的区别就是等程序需要用到这个对象的时候,才创建这个对象,这样操作的好处就是可以节省创建实例的成本以及避免一个项目中要用到多个单例模式,这样就要同时产生多个单个实例,会导致程序启动变慢。
//懒汉模式
class SinlgetonLazy {private static SinlgetonLazy instance = null;public static SinlgetonLazy getInstance() {if(instance == null) {instance = new SinlgetonLazy();}return instance;}private SinlgetonLazy() {}
}
public class Deom23 {public static void main(String[] args) {SinlgetonLazy s1 = SinlgetonLazy.getInstance();SinlgetonLazy s2 = SinlgetonLazy.getInstance();System.out.println(s1 == s2);}
}

1.4两种模式的线程安全

1.4.1饿汉模式——线程安全

原因:由于饿汉模式中的实例化对象是一开始就被创建了,比main线程调用还要早一些,其他线程比main线程还要慢,当其他线程来调用getInstance的时候,只是读取,并不是修改,多个线程同时读取一个变量属于线程安全。

1.4.2懒汉模式——线程不安全

原因:懒汉模式中的实例化对象是什么时候需要用就什么时候调用getIstance,多个线程同时去调用getIstance的时候,getIstance方法中的赋值是一个修改操作,此时就会发生多个线程对同一个变量进行修改操作就会引起线程不安全。
解决方法:加锁

class SinlgetonLazy1 {public static volatile int count = 0;private static SinlgetonLazy1 instance = null;public static SinlgetonLazy1 getInstance() {Object locker = new Object();synchronized(locker) {if (instance == null ) {instance = new SinlgetonLazy1();}}return instance;}private SinlgetonLazy1() {}
}
public class Deom24 {public static void main(String[] args) throws InterruptedException {SinlgetonLazy1 s = SinlgetonLazy1.getInstance();Thread t1 = new Thread(() -> {SinlgetonLazy1 s1 = SinlgetonLazy1.getInstance();});Thread t2 = new Thread(() -> {SinlgetonLazy1 s2 = SinlgetonLazy1.getInstance();});t1.start();t2.start();}
}

在上述代码中有一个缺陷的地方就是给加锁的时候其实只有在线程第一次调用的时候需要加锁,第二次就是读操作不是修改操作了,毕竟频繁加锁也是一个耗资源的操作,所以我们可以加一个判断来解决这个缺陷。

class SinlgetonLazy1 {public static volatile int count = 0;private static SinlgetonLazy1 instance = null;public static SinlgetonLazy1 getInstance() {Object locker = new Object();if(instance == null) {synchronized(locker) {if (instance == null ) {instance = new SinlgetonLazy1();}}}return instance;}private SinlgetonLazy1() {}
}
public class Deom24 {public static void main(String[] args) throws InterruptedException {SinlgetonLazy1 s = SinlgetonLazy1.getInstance();Thread t1 = new Thread(() -> {SinlgetonLazy1 s1 = SinlgetonLazy1.getInstance();});Thread t2 = new Thread(() -> {SinlgetonLazy1 s2 = SinlgetonLazy1.getInstance();});t1.start();t2.start();}
}

此处有两个if而且内容是一样的,但是表达的意义是不一样的,第一个if是判断线程是否需要加锁,第二个if是指是否创造对象。

2.2.阻塞队列

2.1概念

其实就是一个带有阻塞效果先进先出的队列,队列在生产者消费者模型充当一个媒介的身份。

2.2两种队列

2.2.1阻塞队列

队空的时候会阻塞和队满的时候会阻塞的先进先出的队列,在一个进程中直接使用阻塞队列实现生产者消费者模型

2.2.2消息队列

是一个带有标识的先进先出的队列,当让某一个类型的元素出的时候,其他类型的元素会阻塞,在分布式系统中使用单独部署的消息队列服务器实现生产者消费者模型。

2.3模拟实现阻塞队列

public class MyBlockingQueue {public static int count;public int rear;public int front;public int size = 0;public int[] array;public MyBlockingQueue(int Capacity) {this.array = new int[Capacity];}public void put(int value) throws InterruptedException {synchronized (this) {while(size >= array.length) {this.wait();}array[rear] = value;rear = (rear+1) % array.length;size++;//唤醒take线程的阻塞this.notify();}}public int take() throws InterruptedException {synchronized(this) {while(size == 0) {this.wait();}int ret = array[front];front = (front+1) % array.length;size--;//唤醒put线程的阻塞this.notify();return ret;}}//生产者消费者模型public static void main(String[] args) {MyBlockingQueue myBlockingQueue = new MyBlockingQueue(100);//消费者1Thread t1 = new Thread(() -> {try {while (true) {Thread.sleep(1000);myBlockingQueue.take();System.out.println("消费者消费了一个:"+ count);}} catch (InterruptedException e) {throw new RuntimeException(e);}});//消费者2Thread t2 = new Thread(() -> {try {while (true) {Thread.sleep(1000);myBlockingQueue.take();System.out.println("消费者消费了一个:"+ count);}} catch (InterruptedException e) {throw new RuntimeException(e);}});//生产者Thread t3 = new Thread(() -> {try {while(true) {myBlockingQueue.put(count);System.out.println("生产者生产一个:"+ count);count++;}} catch (InterruptedException e) {throw new RuntimeException(e);}});//t1.start();t2.start();t3.start();}
}

在这里插入图片描述
上述图片中,为什么选择while不选择if,原因在于:
当其他线程中有interrupt打断wait方法,则wait方法就会停止阻塞状态,继续往下执行throws操作,那么就会继续添加元素,那么就有可能会覆盖之前的元素,出现bug。而用while就会避免者种情况发生,while就会再一次判断是否满足条件从而就不会发生if出现的情况。
总结:在使用wait的时候最好搭配while不要搭配if。

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

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

相关文章

Android Studio环境搭建(4.03)和报错解决记录

1.本地SDK包导入 安装好IDE以及下好SDK包后,先不要管IDE的引导配置,直接新建一个新工程,进到开发界面。 SDK路径配置:File---->>Other Settings---->>Default Project Structure 拷贝你SDK解压的路径来这,…

ros笔记01--初次体验ros2

ros笔记01--初次体验ros2 介绍安装ros2测试验证ros2说明 介绍 机器人操作系统(ROS)是一组用于构建机器人应用程序的软件库和工具。从驱动程序和最先进的算法到强大的开发者工具,ROS拥有我们下一个机器人项目所需的开源工具。 当前ros已经应用到各类机器人项目开发中…

操作符详解(下) (C语言)

操作符详解下 操作符的属性1.优先级2.结合级 表达式求值1.整型提升2.如何进行整形提升呢?3.算术转换4.问题表达式解析 操作符的属性 C语言的操作符有2个重要的属性:优先级、结合性,这两个属性决定了表达式求值的计算顺序。 1.优先级 优先级…

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

RabbitMQ 进程内流控(Flow Control) 源码解析

1. 概述 1.1 为什么要流控? 流控主要是为了防止生产者生产消息速度过快,超过 Broker 可以处理的速度。这时需要暂时限制生产者的生产速度,让 Broker 的处理能够跟上生产速度。 Erlang进程之间不共享内存,每个进程都有自己的进程邮…

42.HOOK引擎核心代码

上一个内容:41.HOOK引擎设计原理 以 40.设计HOOK引擎的好处 它的代码为基础进行修改 主要做的是读写寄存器 效果图 添加一个类 htdHook.h文件中的实现 #pragma once class htdHook { public:htdHook(); };htdHook.cpp文件中的实现: #include "…

独辟蹊径:我是如何用Java自创一套工作流引擎的(下)

作者:后端小肥肠 创作不易,未经允许严禁转载。 姊妹篇:独辟蹊径:我是如何用Java自创一套工作流引擎的(上)_java工作流引擎-CSDN博客 1. 前言 在上一篇博客中,我们详细介绍了如何利用Java语言从…

LC437.路径总和Ⅲ、LC207.课程表

给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点&am…

【每日刷题】Day77

【每日刷题】Day77 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. LCR 159. 库存管理 III - 力扣(LeetCode) 2. LCR 075. 数组的相对排序 - 力…

Linux——passwd文件,grep,cut

/etc/passwd文件含义 作用 - 记录用户账户信息:共分为7段,使用冒号分割 含义 - 文件内容意义:账户名:密码代号x:UID:GID:注释:家目录:SHELL - 第7列/sbin/nologin&#x…

c++(三)

1. STL 1.1. 迭代器 迭代器是访问容器中元素的通用方法。如果使用迭代器,不同的容器,访问元素的方法是相同的;迭代器支持的基本操作:赋值()、解引用(*)、比较(和!&…

隐私计算实训营第二期第11讲组件介绍与自定义开发

首先给大家推荐一个博主的笔记:隐语课程学习笔记11- 组件介绍与自定义开发-CSDN博客 官方文档:隐语开放标准介绍 | 开放标准 v1.0.dev240328 | 隐语 SecretFlow 01 隐语开放标准 隐语开放标准是为隐私保护应用设计的协议栈。 目前,隐语开…

mysql8.0-学习

文章目录 mysql8.0基础知识-学习安装mysql_8.0登录mysql8.0的体系结构与管理体系结构图连接mysqlmysql8.0的 “新姿势” mysql的日常管理用户安全权限练习查看用户的权限回收:revoke角色 mysql的多种连接方式socket显示系统中当前运行的所有线程 tcp/ip客户端工具基于SSL的安全…

Wp-scan一键扫描wordpress网页(KALI工具系列三十二)

目录 1、KALI LINUX 简介 2、Wp-scan工具简介 3、信息收集 3.1 目标IP(服务器) 3.2kali的IP 4、操作实例 4.1 基本扫描 4.2 扫描已知漏洞 4.3 扫描目标主题 4.4 列出用户 4.5 输出扫描文件 4.6 输出详细结果 5、总结 1、KALI LINUX 简介 Kali Linux 是一…

STM32CubeIDE使用标准库

以STM32F030为例使用标准库文件。 1、新建工程,选择需要使用配置的型号。 2、在工程选型中,选择新建空工程。 3、新建空工程 新建完成,系统只有main函数和启动文件.s有用。 4、启动文件 启动文件,同样是一个汇编文件&#xf…

【Matlab函数分析】imread从图形文件读取图像

🔗 运行环境:Matlab 🚩 撰写作者:左手の明天 🥇 精选专栏:《python》 🔥 推荐专栏:《算法研究》 #### 防伪水印——左手の明天 #### 💗 大家好🤗&#x1f91…

如何利用AI生成可视化图表(统计图、流程图、思维导图……)免代码一键绘制图表

由于目前的AI生成图表工具存在以下几个方面的问题: 大多AI图表平台是纯英文,对国内用户来说不够友好;部分平台在生成图表前仍需选择图表类型、配置项,操作繁琐;他们仍需一份规整的数据表格,需要人为对数据…

软件框架(Framework)是什么?

可实例化的、部分完成的软件系统或子系统,它为一组系统或子系统定义了统一的体系结构(architecture),并提供了构造系统的基本构造块(building blocks),还为实现具体功能定义了扩展点(extending points)。 框架实现了体系结构级别的复用。 其…

系统工程与信息系统基础(上)

目录 系统工程 霍尔三维结构的三维: 切克兰德方法: 并行工程方法: 综合集成法: WSR系统方法: 系统工程生命周期阶段 探索性阶段 概念阶段 开发阶段 生产阶段 使用阶段 保障阶段 退役阶段 系统工程生命周…

初识HTML

HTML语法规范 1、HTML标签是由尖括号包围的关键字&#xff0c;例如<html>。 2、HTML标签通常成对出现&#xff0c;例如<html></html>&#xff0c;此为双标签&#xff0c;标签对的第一个标签是开始标签&#xff0c;第二个标签是结束标签。 3、有些特殊标签…