多线程篇六

多线程篇六

如笔者理解有误欢迎交流指正~⭐


什么是单例模式?

单例模式是最常见的 设计模式.
顾名思义,单例模式指的就是单个实例的模式.(针对某些类只能使用一个对象的场景【如MySQL、JDBC、DataSource】)

设计模式

设计模式是针对某些问题场景而产生的处理问题的方法.(就跟你想吃早饭,可以选择自己做或者出去买或者蹭别人或者别的解决方法一样)
tips
单例模式是线程安全的,能保证某个类在程序中只存在唯一一份实例而不会创建出多个实例.

单例模式又分为饿汗和懒汉两种.

饿汉模式

创建的比较早,类加载时就创建出了.

class Singleton {private static Singleton instance = new Singleton();private Singleton(){}public static Singleton getInstance() {return instance;}
}public class TestSingleton {public static void main(String[] args) {Singleton.getInstance();Singleton s = new Singleton();}
}

注意
1.将instance 设为静态成员,在Singleton类被加载的时候进行实例创建(类加载创建)
2.通过此方法获取new出来的实例,其他代码块后续想一直使用这个类(获取这个类唯一的实例),使用getInstance方法即可.
3.private Singleton() {} 是在设置私有构造方法,保证其它代码不能创建出新的对象.

img

懒汉模式

创建的比较迟,首次使用的时候才创建.

单线程版
class SingletonLazy {//先将引用初始化为null 不立即创建实例private static SingletonLazy instance = null;private static SingletonLazy getInstance() {if(instance == null) {instance = new SingletonLazy();}return instance;}private SingletonLazy() { }
}

注意
1.首次使用instance的时候才真正创建实例.(不调用就不创建)
2.第一次调用getInstance时,instance引用为null,进入if创建出的实例可以持续调用的实例.

对比

1.懒汉模式比饿汉模式效率更高.

2.饿汉模式更具线程安全,饿汉模式getInstance只进行读取,懒汉模式对数据既会读取数据又会修改数据.

线程安全问题发生在首次创建实例时,如果多个线程同时调用getInstance方法对变量进行修改就可能导致线程安全问题.
怎么解决呢?synchronized!

多线程版
class Singleton {private static Object locker = new Object();private static Singleton instance = null;private Singleton() {}public static Singleton getInstance() {synchronized(locker) {if(instance == null) {instance = new Singleton();}}return instance;}
}

问题来了😀.这么写后续每次调用getInstance都需要先加锁,但实际上懒汉模式线程安全问题只出现在new对象时,一但对象new出来后续多线程调用getInstance只有读操作了,就不存在线程安全问题了.【加锁就可能涉及到锁冲突一冲突就会引起阻塞和高性能无缘】
解决方案

class Singleton {private static Object locker = new Object();private static Singleton instance = null;private Singleton() {}public static Singleton getInstance() {if (instance == null) {//第一个if判定的是是否加锁(保证执行效率)synchronized(locker) {if(instance == null) {//第二个if判定的是是否要创建对象(保障线程安全)instance = new Singleton();}}}return instance;}
}

在外层再加一层if判断(如果instance为null,即为首次调用->是否需要加锁,非null->后续会调用->不用加锁)
但是又有惊喜来了!指令重排序!

instacnce = new Singleton();

这条语句执行有三个指令
1.申请一段内存空间
2.在内存上调用构造方法,创建出实例
3.把内存地址赋值给instance
前面给大家介绍过,这些指令正常情况下按顺序执行,但CPU 可以会自己进行优化打乱顺序.
怎么解决?
volatile关键字!(防止指令重排序)

class Singleton {private static Object locker = new Object();private static volatile Singleton instance = null;private Singleton() {}public static Singleton getInstance() {if (instance == null) {//第一个if判定的是是否加锁(保证执行效率)synchronized(locker) {if(instance == null) {//第二个if判定的是是否要创建对象(保障线程安全)instance = new Singleton();}}}return instance;}
}
阻塞队列
什么是阻塞队列

阻塞队列是一种特殊的队列,遵守”先进先出”原则.【典型的生产者消费者模型】

特性

1.队列满的时候继续入队会阻塞,直到有其他线程从队列中取走元素.
2.队列空时继续出队也会阻塞,直到有其他线程王队列中插入元素.

生产者消费者模型

分布式系统在实际开发中经常涉及,核心是分开工作发挥效果.服务器整个功能的实现是由每个服务器单独负责一部分工作实现的,通过各个服务器之间的网络通信完成整个功能.
img
注意
1.上述的阻塞队列是基于对应数据结构实现的服务器程序,被部署到单独的主机上.整个系统的结构更复杂.
2.引入阻塞队列在A发送请求到B接收是有开销损耗的.

解耦合

阻塞队列能使生产者和消费者解耦合.
高考完的暑假想赚点小钱,你和你的朋友开始摆摊卖冰汤圆,每个人都有明确的分工.(是的我是大馋丫头)小A负责采购材料,小B负责制作,小C负责配送,你负责宣传和看城管.顾客是“消费者”,不需要关注你们作为“生产者”谁做了冰汤圆.有吃就行.

削峰填谷

阻塞队列相当于一个缓冲区,平衡了生产者和消费者之间的处理能力.
618大抢购,一分钟之内可能会产生数百万订单,服务器在同一时刻收到大量的支付请求,直接处理服务器受不了会崩溃,(一个请求耗费的资源少但积累量变产生质变,任何一种硬件资源达到瓶颈服务器都会寄)
这时候就是阻塞队列大显身手的时候,将请求都放到一个阻塞队列中,然后再由消费者线程慢慢来处理每个支付请求.

代码实现
public class TestCustomerAndProducer {public static void main(String[] args) {BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<Integer>();Thread customer = new Thread(() -> {while(true) {try {int value = blockingQueue.take();System.out.println("Consumption element: " + value);Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}, "customer");Thread producer = new Thread(() -> {Random r = new Random();while(true) {try {int num = r.nextInt(1000);System.out.println(" Production elements: " + num);blockingQueue.put(num);Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}}}, "procedure");customer.start();producer.start();}
}
实现阻塞队列
import java.util.Random;public class BlockingQueue {public int[] elems = new int[2000];private volatile int size = 0;private volatile int head = 0;private volatile int tail = 0;private Object locker = new Object();public synchronized int getSize() {return size;}public void put(int value) throws InterruptedException{synchronized(locker){while(size >= elems.length) {//满 阻塞等待locker.wait();}elems[tail] = value;tail = (tail + 1) % elems.length;size++;//入队后唤醒locker.notify();}}public int take() throws InterruptedException {int ret = 0;synchronized(locker) {while(size <= 0) {//队列空继续阻塞locker.wait();}ret = elems[head];head = (head + 1) % elems.length;size--;//出队成功后唤醒locker.notify();}return ret;}
}

注意
1.使用循环队列实现(注意理解头指针和尾指针的变化)
2.put和take使用的是同一把锁,若队列被put满之后又唤醒了另一个阻塞的put就会出bug,加while判断,如果队列一直是慢的就不再被唤醒,保证安全性.

标准库中的阻塞队列

在 Java 标准库中内置了阻塞队列. 如果我们需要在一些程序中使用阻塞队列, 直接使用标准库中的即可.
1.BlockingQueue 是一个接口. 真正实现的类是 LinkedBlockingQueue.
2.put 方法用于阻塞式的入队列, take 用于阻塞式的出队列.
3.BlockingQueue 也有 offer, poll, peek 等方法, 但是这些方法不带有阻塞特性.

public class BlockingQueue {public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue = new LinkedBlockingQueue<>();//入队列queue.put("abc");//出队列.如果没有put直接take,会阻塞.String elem = queue.take();System.out.println(elem);}
}

未完待续🌟(●’◡’●)

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

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

相关文章

数据结构之二叉树(1)

数据结构之二叉树&#xff08;1&#xff09; 一、树 1、树的概念与结构 &#xff08;1&#xff09;树是一种非线性的数据结构&#xff0c;由n(n>0)个有限结点组成一个具有层次关系的集合。 &#xff08;2&#xff09;树有一个特殊的结点&#xff0c;叫做根结点&#xff…

Linux:Bash中的文件描述符

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 Linux中的所有进程&#xff0c;都拥有自己的文件描述符(File Descriptor, FD)&#xff0c;它是操作系统在管理进程和文件时的一种抽象概念。每个文件描述符由一个非负整…

【Mac】系统环境配置

常用工具 Navicat PJ版本&#xff1a;this 提取密码&#xff1a;v31p Host切换器 SwitchHosts termius 一款好用的Linux服务器连接工具&#xff1a; termius 小飞机 dddd&#xff1a;&#x1fa9c; Git mac安装git有好多种方式&#xff0c;自带的xcode或者通过Homebr…

[数据集][目标检测]智慧交通铁路异物入侵检测数据集VOC+YOLO格式802张7类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;802 标注数量(xml文件个数)&#xff1a;802 标注数量(txt文件个数)&#xff1a;802 标注类别…

pytorch快速入门(一)—— 基本工具及平台介绍

前言 该pytorch学习笔记应该配合b站小土堆的《pytorch深度学习快速入门教程》使用 环境配置&#xff1a;Anaconda Python编译器&#xff1a;pycharm、jupyter 两大法宝函数 dir&#xff08;&#xff09;&#xff1a;知道包中有什么东西&#xff08;函数 / 属性..…

C++的封装

手动封装一个顺序表&#xff08;SeqList&#xff09;,分文件编译实现 有私有成员&#xff1a;顺序表数组的起始地址 ptr、 顺序表的总长度&#xff1a;size、顺序表的实际长度&#xff1a;len 成员函数&#xff1a;初始化 init(int n) 判空&#xff1a;empty 判满&#xff1a;f…

【计算机网络 - 基础问题】每日 3 题(一)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

云手机的便捷性和安全性体现在哪?

随着5G技术的迅速发展&#xff0c;云手机在游戏、电商以及新媒体营销等领域中的应用日益广泛。它不仅能够显著降低成本、提升效率&#xff0c;还随着边缘计算和云技术的进步&#xff0c;展现出无限的增长潜力。 云手机的便捷性体现在哪里&#xff1f; 云手机的便捷性毋庸置疑。…

基于ExtendSim的 电子制造 仿真模型

说明&#xff1a; 此模型表示电路板制造设施。该过程有4个步骤&#xff1a; *焊料制备 *组件放置 *烤箱 *检查 详情&#xff1a; *烤箱的容量为10张卡&#xff0c;但如果烤箱循环开始时仅能处理5张卡&#xff0c;则最多只能处理5张。 *如果检查员发现问题&#xff0c;他们将修理…

大数据新视界 --大数据大厂之 Cassandra 分布式数据库:高可用数据存储的新选择

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【matlab】将程序打包为exe文件(matlab r2023a为例)

文章目录 一、安装运行时环境1.1 安装1.2 简介 二、打包三、打包文件为什么很大 一、安装运行时环境 使用 Application Compiler 来将程序打包为exe&#xff0c;相当于你使用C编译器把C语言编译成可执行程序。 在matlab菜单栏–App下面可以看到Application Compiler。 或者在…

数据结构和算法之线性结构

原文出处:数据结构和算法之线性结构 关注码农爱刷题&#xff0c;看更多技术文章&#xff01;&#xff01;&#xff01; 线性结构是一种逻辑结构&#xff0c;是我们编程开发工作应用最广泛的数据结构之一。线性结构是包含n个相同性质数据元素的有限序列。它的基本特征是&…

docker入门安装及使用

docker概述 docker是一种容器技术&#xff0c;它提供了标准的应用镜像&#xff08;包含应用和应用多需要的依赖&#xff09;&#xff0c;因此&#xff0c;我们可以非常轻松的在docker中安装应用&#xff0c;安装好的应用相当于一个独立的容器 如下图所示&#xff0c;为docker中…

如何将Git本地代码推送到Gitee云端仓库

如何将Git本地代码推送到Gitee云端仓库 在使用Git进行版本控制时&#xff0c;将本地代码推送到远程仓库是一个基本且重要的操作。本文将详细介绍如何将你的Git本地代码推送到Gitee&#xff08;码云&#xff09;云端仓库。Gitee是一个国内非常流行的代码托管平台&#xff0c;类…

Redis 执行 Lua,能保证原子性吗?

前言 小张目前在使用分布式锁 Redisson 实现一个需求。那我在想我能否自己手撸一个能用于分布式环境的锁呢&#xff1f;于是果然尝试。 历经一天后&#xff0c;小张手撸的锁终于写出来了&#xff0c;再次给各位看看&#xff0c;看给位有没有什么优化的建议&#xff1a; // 加…

VSCode 定义代码模板

在使用编写代码的过程中&#xff0c;经常会写一些固定代码段。 以 Java 为例&#xff0c;定义实体类时一般都会编写序列化版本号&#xff1a; Serial private static final long serialVersionUID 1L;这段代码是固定写法&#xff0c;基本不会变&#xff0c;如果每次都手写的…

sqlgun靶场漏洞挖掘

1.xss漏洞 搜索框输入以下代码&#xff0c;验证是否存在xss漏洞 <script>alert(1)</script> OK了&#xff0c;存在xss漏洞 2.SQL注入 经过测试&#xff0c;输入框存在SQL注入漏洞 查询数据库名 查询管理员账号密码 此处密码为MD5加密&#xff0c;解码内容如下 找…

使用Python免费将pdf转为docx

刚刚想将pdf转换为docx文档时&#xff0c;居然要收费 还好我学过编程&#xff0c;这不得露两手 将pdf 转换为 docx 文档 的操作步骤 我这里使用的是Python语言 &#xff08;1&#xff09;在终端上安装 pdf2docx 是一个 Python 库&#xff0c;它可以将 PDF 文件转换为 Word (…

【JS】postMessage与MessageChannel

前言 postMessage 和 MessageChannel 都是用来实现跨文档、跨窗口或跨线程&#xff08;Web Worker&#xff09;的消息传递机制。 postMessage 可以在 iframe、同源或跨源窗口之间传递数据&#xff0c;也可以用于主线程与 Web Worker 之间的通信。 postMessage 是一种单向的…

IP包头分析

IP包头 选择自己的网卡&#xff0c;开始抓包 ping一个字节大点的数据&#xff0c;方便查看包 选择数据包&#xff0c;并过滤icmp协议 查看抓到的包&#xff0c;分析 IP包头范围&#xff1a;20-60 首部长度&#xff1a;定义包头的长度 总长度&#xff1a;表示当前数据的长度…