多线程篇六

多线程篇六

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


什么是单例模式?

单例模式是最常见的 设计模式.
顾名思义,单例模式指的就是单个实例的模式.(针对某些类只能使用一个对象的场景【如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;它是操作系统在管理进程和文件时的一种抽象概念。每个文件描述符由一个非负整…

能否通过 cuda 安装cudatoolkit 以及通过 pip 安装 torch 呢?

能否通过 cuda 安装cudatoolkit 以及通过 pip 安装 torch 呢? 如题目所述, 本人新建了一个c onda 虚拟环境. 这个虚拟环境中使用 pip 命令安装了 torch 等一系列库, 然后在安装 mvcc 时遇到了… 文章没有写完, 因为我突然发现我的 mvcc 安装成功了, 然后我就没有往下深究

UAC2.0 麦克风——多采样率支持

UAC2.0 麦克风系列文章 UAC2.0 麦克风——单声道 USB 麦克风(16bit) UAC2.0 麦克风——类特殊请求 UAC2.0 麦克风——音量控制 UAC2.0 麦克风——多采样率支持 UAC2.0 麦克风——24/32bit 支持 UAC2.0 麦克风——麦克风数据传输 UAC2.0 麦克风——同时支持 16bit,24bit 和 …

【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; 云手机的便捷性毋庸置疑。…

Python Flask网页开发基本框架

注&#xff1a;Flask详细学习请见Flask学习合集。 直接上代码: app.py from flask import Flaskapp Flask(__name__)app.route("/") def hello():return "Hello, World!"if __name__ "__init__":app.run(host "127.0.0.1", port…

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

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

精密运放与普通运放的区别

精密运放和普通运放之间的区别主要体现在性能、设计、应用场合以及关键参数上。以下是对这些区别的详细阐述&#xff1a; 一、性能差异 放大倍数与精度&#xff1a; 精密运放&#xff1a;具有更高的开环放大倍数&#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;类…

git删除本地+远程提交记录

//撤销本地仓库提交 1.git log 2.git reset --soft 指定commit版本号 git reset --soft "版本号"&#xff1a;重置至指定版本的提交。这里我们指定版本号为 ②&#xff0c;从而达到撤销 ①的目的。 参数 soft&#xff1a;保留当前工作区&#xff08;代码和文…

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

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