【JavaEE初阶】多线程(5 单例模式 \ 阻塞队列)

news2024/11/24 20:25:12

欢迎关注个人主页:逸狼


创造不易,可以点点赞吗~

如有错误,欢迎指出~



目录

实例1: 单例模式

饿汉模式

懒汉模式

实例2:阻塞队列

生产者消费者模型 

优点

​编辑 代价

简单实现一个生产者消费者模型 

Java标准库中的阻塞队列

​编辑 模拟实现一个阻塞队列


实例1: 单例模式

单例模式 是一种设计模式,(固定套路,针对一些特定的场景,给出的一些比较好的解决方案)

开发中,希望有的类在一个进程中,不应该存在多个实例(对象),此时就可以使用单例模式(单个实例/对象),限制某个类只能有唯一实例, 比如 一般来说,一个程序 只有一个数据库,对应的mysql服务器只有一份,此时DataSource这个类就没有必要创建出多个实例了,此时使用单例模式描述DataSource,避免不小心创建出多个实例

Java中单例模式的实现有很多种,下面介绍两种最主流的写法: 饿汉模式 和 懒汉模式

饿汉模式

程序启动,在类被加载的时候, 就会创建出这个单例的实例, 不涉及线程安全问题

// 创建一个单例的类
// 饿汉方式实现.
// 饿 的意思是 "迫切"
// 
class Singleton{
    private static Singleton instance =new Singleton();

    public static Singleton getInstance(){
        return instance;
    }

    //单例模式的 最关键部分
    private Singleton(){

    }
}

 

单例模式只能避免别人"失误",无法应对别人的"故意攻击"(可以通过 反射 和 序列化反序列化打破上述单例模式)

懒汉模式

推迟了创建实例的时机,在程序第一次使用这个实例的时候 才会创建实例 ,涉及线程安全问题

class SingletonLazy{
    //此处先把实例设为null,先不着急创建实例
    private static volatile SingletonLazy instance =null;
    private static Object locker =new Object();
    public static SingletonLazy getInstance(){
        if(instance==null){
            synchronized(locker){
                if(instance==null){
                    instance = new SingletonLazy();
                }
            }
        }
        return instance;
    }
    private SingletonLazy(){ }
}

可能存在的线程安全问题

通过加锁解决,将if判定和new赋值操作,打包成原子操作  

 

双重if 判定 , 通过if条件判定是否要加锁 

编译器优化(指令重排序) 造成的线程安全问题

在执行3)步骤之后并且未执行2)步骤时 如果线程发生切换,此时会直接返回instance,但是这个被返回的对象是没有被初始化的,由于该对象未初始化,一旦调用该对象里的成员,都可能是错误的值,引起一系列不可预期的情况.

解决方法:在instace的前面加上volatile.

实例2:阻塞队列

阻塞队列 是在普通队列(先进先出)的基础上做出扩充:

  • 线程安全  (标准库中原有的队列Queue和其子类,默认都是线程不安全的)
  • 具有阻塞特性  
    • 如果队列为,进行出队列操作 就会出现阻塞,一直阻塞到其他线程往队列里添加元素为止
    • 如果队列为,进行入队列操作 也会出现阻塞,一直阻塞到其他线程从队列中取走元素为止

生产者消费者模型 

该模型是基于阻塞队列的最大应用场景

优点

使用该模型的优点:

1,有利于服务器之间的"解耦合"

 2,通过中间的阻塞队列,可以起到"削峰填谷"的效果(在遇到请求量激增的情况下,可以有效保护下游服务器,不会被请求冲垮)

通常谈到的"阻塞队列"是代码中的一个数据结构,但是由于这个东西太好用了,以至于被单独封装成了一个服务器程序,并且在单独的服务器机器上部署,此时这样的阻塞队列有了一个新的名字:"消息队列"(Message Queue ,MQ) 

 代价

  • 需要更多的机器 来部署这个消息队列
  • A和B之间的通信延时 会变长

简单实现一个生产者消费者模型 

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Demo27 {
    public static void main(String[] args) {
        // BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(1000);
        MyBlockingQueue queue = new MyBlockingQueue(1000);

        // 生产者线程
        Thread t1 = new Thread(() -> {
            int i = 1;
            while (true) {
                try {
                    queue.put("" + i);
                    System.out.println("生产元素 " + i);
                    i++;

                    // 给生产操作, 加上 sleep, 生产慢点, 消费快点
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        // 消费者线程
        Thread t2 = new Thread(() -> {
            while (true) {
                try {
                    Integer i = Integer.parseInt(queue.take());
                    System.out.println("消费元素 " + i);

                    // 给消费操作, 加上 sleep, 生产快点, 消费慢点
                    // Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        t1.start();
        t2.start();
    }
}

Java标准库中的阻塞队列

入队列产生阻塞效果,代码演示

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Demo18 {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue=new ArrayBlockingQueue<>(3);
        queue.put("111");
        System.out.println("put成功");
        queue.put("111");
        System.out.println("put成功");
        queue.put("111");
        System.out.println("put成功");
        queue.put("111");
        System.out.println("put成功");
    }
}

 模拟实现一个阻塞队列

 基于数组实现的一个阻塞队列


class MyBlockingQueue{
    private String[] data=null;
    private volatile int head =0;
    private volatile int tail =0;
    private volatile int size =0;

    public MyBlockingQueue(int capacity){
        data = new String[capacity];
    }

    public void put(String s) throws InterruptedException {
        synchronized (this){
            //下面有大量的修改操作,加上锁保证线程安全
            //可以单独定义一个锁对象,也可以使用this表示当前对象
            while(size == data.length){
                //队列满了
//                return;
                this.wait();
            }
            data[tail]=s;
            tail++;
            if(tail >= data.length){
                tail=0;//如果tail移到了末尾,直接让tail到0位置,构成循环队列
            }
            size++;

            this.notify();
        }
    }

    public String take() throws InterruptedException {
        String ret= "";
        synchronized (this){
            while(size == 0){
//                return null;
                this.wait();
            }
             ret = data[head];

            head++;
            if(head>=data.length){
                head = 0;
            }
            size--;

            this.notify();
        }
        return ret;
    }
}

注意:要将使用wait时的if判断换成while循环,使代码更加稳健

while 的作用,就是在wait被唤醒之后再次确认条件,看是否能继续执行

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

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

相关文章

面试官问:你如何看待加班?

面试官问&#xff1a;你如何看待加班&#xff1f; 面试官问&#xff1a;你如何看待加班&#xff1f;这类问题是比较常见的&#xff0c;出现频率相当高。有些同学看到这样的问题&#xff0c;就会断定这家公司估计是经常加班的&#xff0c;绝对的不能去&#xff01;&#xff01;…

通信工程学习:什么是PON无缘光纤网络

PON&#xff1a;无源光纤网络 PON&#xff08;Passive Optical Network&#xff0c;无源光纤网络&#xff09;是一种采用光分路器等无源光器件进行信号传输和分配的光纤接入技术。它利用光纤作为传输媒介&#xff0c;通过无源设备将光信号从中心局&#xff08;如光线路终端OLT&…

中秋节特别游戏:给玉兔投喂月饼

&#x1f5bc;️ 效果展示 &#x1f4dc; 游戏背景 在中秋这个充满诗意的节日里&#xff0c;玉兔因为贪玩被赶下人间。在这个温柔的夜晚&#xff0c;我们希望通过一个小游戏&#xff0c;让玉兔感受到人间的温暖和关怀。&#x1f430;&#x1f319; &#x1f3ae; 游戏设计 人…

太阳能光伏板航拍红外图像缺陷分类数据集

太阳能光伏板航拍红外图像缺陷分类数据集 一、数据集简介 太阳能光伏板的性能直接影响到光伏发电系统的效率和可靠性。随着无人机和红外成像技术的发展&#xff0c;通过航拍红外图像对光伏板进行缺陷检测已成为一种高效且准确的方法。本数据集包含11种不同的缺陷分类&#xf…

【CPP】模板(后篇)

目录 13.1 非类型模板参数13.2 函数模板的特化13.3 类模板的特化13.4 模板的分离编译 这里是oldking呐呐,感谢阅读口牙!先赞后看,养成习惯! 个人主页:oldking呐呐 专栏主页:深入CPP语法口牙 13.1 非类型模板参数 顾名思义,非类型模板参数就是一个模板的参数,只不过不是类型,而…

第二十六篇——九地篇:九种形势的应对之道

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 地势的维度重新阐述了懂得人心的重要性&#xff0c;道久其归一为为别人。…

个人随想-gpt-o1大模型中推理链的一个落地实现

​首先祝大家中秋节快乐。 最近openai又推出了新的模型openai o1​还有它的mini版。官网的介绍&#xff0c;就是它的推理能力很强&#xff0c;比gpt-4o​有很大的提升。 最近也跟同行在聊这个o1&#xff0c;​看看落地方面有哪些可行性。在我们自己的实验上&#xff0c;把o1用…

Python画笔案例-052 绘制彩色递归六边形

1、绘制彩色递归六边形 通过 python 的turtle 库绘制 彩色递归六边形&#xff0c;如下图&#xff1a; 2、实现代码 绘制彩色递归六边形&#xff0c;以下为实现代码&#xff1a; """彩色递归六边形.py """ import turtledef draw_circle(radius,…

【自动化测试】移动app的分层测试以及自动遍历的基本概念

引言 移动应用的分层测试是一种系统化的测试方法&#xff0c;它将测试过程分解为不同的层次&#xff0c;以确保应用在每个层面上都符合设计要求和用户期望 文章目录 引言一、移动app的分层测试1.1 单元测试&#xff08;Unit Testing&#xff09;1.2 集成测试&#xff08;Integr…

甲骨文创始人埃里森:人工智能终有一天会追踪你的一举一动

9月17日消息&#xff0c;据外电报道&#xff0c;甲骨文创始人拉里埃里森在甲骨文财务分析师会议上表示&#xff0c;他预计人工智能有一天将为大规模执法监控网络提供动力。“我们将进行监督。”他说。“每一位警察都将随时受到监督&#xff0c;如果有问题&#xff0c;人工智能会…

人工智能辅助汽车造型设计

随着科技的不断进步&#xff0c;人工智能&#xff08;AI&#xff09;在各个领域的应用越来越广泛&#xff0c;汽车设计行业也不例外。尤其在车辆外观造型设计中&#xff0c;AI正在成为设计师的重要助手&#xff0c;通过提供强大的工具和独特的创意方式&#xff0c;革新了传统设…

算法之搜索--最长公共子序列LCS

最长公共子序列&#xff08;longest common sequence&#xff09;:可以不连续 最长公共子串&#xff08;longest common substring&#xff09;&#xff1a;连续 demo for (int i 1;i<lena;i){for (int j 1;j<lenb;j){if(a[i-1]b[j-1]){dp[i][j]dp[i-1][j-1]1;}el…

神奇的Serializable接口,为什么有时候网络传输不用实现Serializable,有时候又需要?

大家好&#xff0c;这里是小奏,觉得文章不错可以关注公众号小奏技术 背景 其他大家在初学java的时候肯定是接触过Serializable接口的&#xff0c;这个接口是一个标记接口&#xff0c;没有任何方法&#xff0c;只是一个标记&#xff0c;用来标记一个类可以被序列化&#xff0c;…

深入解析代理模式:静态代理、JDK 动态代理和 CGLIB 的全方位对比!

代理模式&#xff08;Proxy Pattern&#xff09;是一种结构型设计模式&#xff0c;它提供了对象的替身&#xff0c;即代理对象来控制对实际对象的访问。通过代理对象&#xff0c;可以在不修改目标对象的情况下&#xff0c;扩展或控制其功能。例如&#xff0c;代理模式可以用于延…

JDBC的介绍和连接MySQL数据库

目录 1. 为什么学习JDBC 1.1 数据存储​编辑​编辑 1.2 数据操作​编辑 2. JDBC概述 2.1 JDBC概念 2.2 JDBC 核心组成 3. 实现 JDBC 3.1 JDBC 搭建步骤 3.2 详细演示 3.3 核心API 3.3.1 Driver​ 3.3.2 Connection​ 3.3.3 Statament​ 3.3.4 PreparedStatement …

嵌入式单片机中can总线调试方法

大家好,今天将向大家介绍如何使用STM32F4自带的CAN控制器实现两个开发板之间的CAN通信。 1.CAN CAN是控制器局域网络(Controller Area Network, CAN)的简称,是由以研发和生产汽车电子产品著称的德国BOSCH公司开发的,并最终成为国际标准(ISO 11898),是国际上应用最广泛的…

大模型笔记03--快速体验dify

大模型笔记03--快速体验dify 介绍部署&测试部署 dify测试dify对接本地ollama大模型对接阿里云千问大模型在个人网站中嵌入dify智能客服 注意事项说明 介绍 Dify 是一款开源的大语言模型(LLM) 应用开发平台。它融合了后端即服务&#xff08;Backend as Service&#xff09;…

优化 OR 条件过多导致的查询超时

优化 OR 条件过多导致的查询超时 文章目录 优化 OR 条件过多导致的查询超时背景问题分析方案分析方案一&#xff1a;入参去重方案二&#xff1a;分页或者分批查询方案三&#xff1a;UNION 代替 OR方案四&#xff1a;IN 代替 OR1. 分别对列进行 IN 查询&#xff0c;在代码中进行…

同一Python脚本中训练多个模型时的 wandb 配置错误解决方案

文章目录 摘要背景介绍报错信息wandb 模型训练名 摘要 在机器学习项目中&#xff0c;使用Python脚本训练多个模型时&#xff0c;可能会遇到WandB&#xff08;Weights and Biases&#xff09;配置错误&#xff0c;尤其是在训练多个模型参数大小不一致的情况下。 本文将介绍如何…

Vue学习记录之三(ref全家桶)

ref、reactive是在 setup() 声明组件内部状态用的&#xff0c; 这些变量通常都要 return 出去&#xff0c;除了供 < template > 或渲染函数渲染视图&#xff0c;也可以作为 props 或 emit 参数 在组件间传递。它们的值变更可触发页面渲染。 ref &#xff1a;是一个函数&…