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

news2024/11/22 8:58:25

在这里插入图片描述
🎏🎏🎏个人主页🎏🎏🎏
🎏🎏🎏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);
        //消费者1
        Thread t1 = new Thread(() -> {
                try {
                    while (true) {
                        Thread.sleep(1000);
                        myBlockingQueue.take();
                        System.out.println("消费者消费了一个:"+ count);
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
        });
        //消费者2
        Thread 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.coloradmin.cn/o/1880183.html

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

相关文章

力扣 单词规律

所用数据结构 哈希表 核心方法 判断字符串pattern 和字符串s 是否存在一对一的映射关系,按照题意,双向连接的对应规律。 思路以及实现步骤 1.字符串s带有空格,因此需要转换成字符数组进行更方便的操作,将字符串s拆分成单词列表…

Linux --账号和权限管理

目录 1、 管理用户账号和组账概述 1.1 用户账号分类 1.2 组账号 1.3 UID 和 GID 2、用户账号文件 2.1 passwd 2.2 shadow 3、管理目录和文件属性 3.1 chage 命令 3.2 useradd 命令 3.3 passwd 命令 ​编辑3.4 usermod 命令 3.5 userdel 命令 4、用户账户的初始配置…

Spring企业开发核心框架-下

五、Spring AOP面向切面编程 1、场景设定和问题复现 ①准备AOP项目 项目名:Spring-aop-annotation ②声明接口 /*** - * / 运算的标准接口!*/ public interface Calculator { int add(int i, int j); int sub(int i, int j); int mul(int i, in…

使用Python绘制太阳系图

使用Python绘制太阳系图 太阳系图太阳系图的优点使用场景 效果代码 太阳系图 太阳系图(Sunburst Chart)是一种层次结构图表,用于表示数据的分层结构。它使用同心圆表示各个层级,中心圆代表最高层级,向外的圆环代表逐级…

类型转换与数据绑定【Spring源码学习】

simpleTypeConverter 类型转换 SimpleTypeConverter typeConverter new SimpleTypeConverter(); Integer number typeConverter.convertIfNecessary("13",int.class); System.out.println(number);BeanWrapper 通过反射原理为bean赋值,走的是set方法…

使用pyqt5编写一个七彩时钟

使用pyqt5编写一个七彩时钟 效果代码解析定义 RainbowClockWindow 类初始化用户界面显示时间方法 完整代码 在这篇博客中,我们将使用 PyQt5 创建一个简单的七彩数字时钟。 效果 代码解析 定义 RainbowClockWindow 类 class RainbowClockWindow(QMainWindow):def _…

C++ 数据库MySQL 学习笔记(3) - 数据库操作

C 数据库MySQL 学习笔记(3) - 数据库操作 视图操作 视图是从一个或多个表中导出来的表,是一种虚拟存在的表。视图就像一个窗口,通过这个窗口可以看到系统专门提供的数据,这样用户可以不看整个数据库表中的数据,而只关心对自己有…

【热部署】✈️Springboot 项目的热部署实现方式

目录 🍸前言 🍻一、热部署和手动重启 🍺二、热部署的实现 2.1 手动启动热部署 2.2 自动检测热部署 2.3 关闭热部署 💞️三、章末 🍸前言 小伙伴们大家好,书接上文,通过Springboot 中的 actu…

【Python】已解决:IndexError: list index out of range

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决:IndexError: list index out of range 一、分析问题背景 在Python编程中,IndexError: list index out of range 是一个常见的错误。这个错误通常出现…

【Python从入门到进阶】59、Pandas库中Series对象的操作(二)

接上篇《58、Pandas库中Series对象的操作(一)》 上一篇我们讲解了Pandas库中Series对象的基本概念、对象创建和操作,本篇我们来继续学习Series对象的运算、函数应用、时间序列操作,以及Series的案例实践。 一、Series对象的运算 1. 数值型数据的算术运…

基于JSP的体育竞赛成绩管理系统

开头语:你好呀,我是计算机学长猫哥!如果有相关需求,文末可以找到我的联系方式。 开发语言:JSP 数据库:MySQL 技术:JSPJava 工具:MyEclipse, Tomcat, MySQL 系统展示 首页 管理…

Windows Ternimal

Windows Ternimal 安装 Windows 终端概述 | Microsoft Learn wt --help在当前目录打开 lextm/windowsterminal-shell: Install/uninstall scripts for Windows Terminal context menu items 打开指定目录 wt -d %USERPROFILE% ohmyposh 美化 1 安装 2 添加 ohmyposh bin…

数字签名解析

1. 概述 数字签名不是手写签名的数字图像; 数字签名是一种可以提供认证的加密形式,是转向完全无纸环境的一个途径; 数字签名机制用以解决伪造、抵赖、冒充和篡改、完整性保护等安全问题。 2. 公钥密码与数字签名的关系 要实现数字签名&#…

【python爬虫实战】爬取豆瓣top250(网站有反爬虫机制肿么办)

关于请求头headers: 值得注意的是,与上一篇 :​​​​​​【python爬虫实战】爬取书店网站的 书名&价格(注释详解)-CSDN博客 爬取书名不同,这次爬取豆瓣网站必须使用“请求头headers”,不然将没有输…

SSM学习2:依赖注入、依赖自动装配、集合注入、加载properties文件

依赖注入 依赖注入方式 setter注入——引用类型 setter注入——简单类型 public class BookDaoImpl implements BookDao {public void setDatabaseName(String databaseName) {this.databaseName databaseName;}public void setNum(int num) {this.num num;}private Stri…

【图像超分辨率】一个简单的总结

文章目录 图像超分辨率(Image Super-Resolution, ISR)1 什么是图像超分辨率?2 图像超分辨率通常有哪些方法?(1)基于插值的方法(2)基于重建的方法(3)基于学习的方法(LR im…

jenkins 发布服务到linux服务器

1.环境准备 1.1 需要一台已经部署了jenkins的服务器,上面已经集成好了,jdk、maven、nodejs、git等基础的服务。 1.2 需要安装插件 pusblish over ssh 1.3 准备一台额外的linux服务器,安装好jdk 2.流程描述 2.1 配置jenkins,包括p…

统计是一门艺术(参数假设检验)

1.参数假设检验 在总体分布已知的情况下,对分布中未知参数的检验。 (1)相关基本概念 零假设/原假设与对立假设/备择假设: 任务:根据样本作出是否接受H0 复合假设与简单假设: 否定域/拒绝域与接受域&…

Python:谈谈常规滤波器(带通、低通、高通、带阻)的用法

一、滤波器的作用 滤波器在信号处理中用于移除或减少信号中的噪声,同时保持信号的某些特性。滤波器通常用于音频、视频和图像处理等领域。滤波器根据其 designed for different purposes and can be divided into several types, such as lowpass filters, highpass…

【Unity设计模式】✨使用 MVC 和 MVP 编程模式

前言 最近在学习Unity游戏设计模式,看到两本比较适合入门的书,一本是unity官方的 《Level up your programming with game programming patterns》 ,另一本是 《游戏编程模式》 这两本书介绍了大部分会使用到的设计模式,因此很值得学习 本…