【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);
        //消费者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。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

维卡币(OneCoin)是投资骗局!中国成维卡币传销重灾区,信徒们醒醒吧!创始人被通缉,生死不明!

维卡币(英文名:OneCoin)是一个隐藏在加密货币外表下的庞氏骗局,因传销诈骗和违法吸金被起诉,受害者遍布全球。它的创始人Ruja Ignatova因欺骗和洗钱被列为通缉嫌疑人,成为全球最大金融诈骗案件之一的逃犯,目前美国政府…

ELK企业级实战

一、Elstic stack在企业的常⻅架构 https://www.bilibili.com/video/BV1x94y1674x/?buvidXY705117E90F73A790429C9CFBD5F70F22168&vd_source939ea718db29535a3847d861e5fe37ef ELK 解决取得问题 痛点1: ⽣产出现故障后,运维需要不停的查看各种不同的⽇志进⾏…

Flutter 入门与实战(十一):底部弹窗ModelBottomSheet详解

这是我参与更文挑战的第6天,活动详情查看: 更文挑战 在实际开发过程中,经常会用到底部弹窗来进行快捷操作,例如选择一个选项,选择下一步操作等等。在 Flutter 中提供了一个 showModelBottomSheet 方法用于弹出底部弹窗,本篇介绍如何使用底部弹窗。 实现效果 最终实现效果…

【使用sudo apt-get出现报错】——无法获得锁 /var/lib/dpkg/lock-open(11:资 源暂时不可用) ,是否有其他进程正占用它?

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、ubuntu中进程正在被占用1. 问题描述2. 原因分析3. 解决 总结 前言 一、ubuntu中进程正在被占用 1. 问题描述 在Ubuntu中,使用终端时输入带有…

50-3 内网信息收集 - 域环境搭建

搭建准备: 在搭建准备阶段,我们需要准备三台 Windows 虚拟机:Windows Server 2012、Windows 7 和 Windows Server 2008。接下来,我们将配置 Windows Server 2012 作为域控制器,而 Windows 7 和 Windows Server 2008 将作为成员机加入域。建议保持这三台虚拟机的内存不超过…

Servlet_Web小结

1.web开发概述 什么是服务器? 解释一:服务器就是一款软件,可以向其发送请求,服务器会做出一个响应. 可以在服务器中部署文件,让他人访问 解释二:也可以把运行服务器软件的计算机也可以称为服务器。 web开发: 指的是从网页中向后…

C++学习全教程(Day2)

一、数组 在程序中为了处理方便,常常需要把具有相同类型的数据对象按有序的形式排列起来,形成“一组”数据,这就是“数组”(array) 数组中的数据,在内存中是连续存放的,每个元素占据相同大小的空间,就像排…

redis实战-添加商户缓存

为什么要使用缓存 言简意赅:速度快,好用缓存数据存储于代码中,而代码运行在内存中,内存的读写性能远高于磁盘,缓存可以大大降低用户访问并发量带来的服务器读写压力实际开发中,企业的数据量,少…

网络编程常见问题

1、TCP状态迁移图 2、TCP三次握手过程 2.1、握手流程 1、TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态; 2、TCP客户进程也是先创建传输控制块TCB&#xff…

RabbitMq教程【精细版一】

一、引言 模块之间的耦合度过高,导致一个模块宕机后,全部功能都不能用了,并且同步通讯的成本过高,用户体验差。 RabbitMQ引言 二、RabbitMQ介绍 MQ全称为Message Queue,消息队列是应用程序和应用程序之间的通信方法。…

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

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

碧海威L7云路由无线运营版 confirm.php/jumper.php 命令注入漏洞复现(XVE-2024-15716)

0x01 产品简介 碧海威L7网络设备是 北京智慧云巅科技有限公司下的产品,基于国产化ARM硬件平台,采用软硬一体协同设计方案,释放出产品最大效能,具有高性能,高扩展,产品性能强劲,具备万兆吞吐能力,支持上万用户同时在线等高性能。其采用简单清晰的可视化WEB管理界面,支持…

python序列

列表 与字符串的索引一样,列表索引从 0 开始,第二个索引是 1,依此类推。 通过索引列表可以进行截取、组合等操作 创建一个列表 list [red, green, blue, yellow, white, black]正向取值 print(list[1])反向取值 print(list[-2])更新列…

吉时利 Keithley2601B-PULSE 脉冲数字源表

Keithley2601B-PULSE吉时利脉冲SMU数字源表 无需手动脉冲调整即可实现高脉冲保真度 通过 2601B-PULSE 控制回路系统,高达 3μH 的负载变化无需手动调整,从而确保在任何电流水平(最高 10 安培)下输出 10 μs 至 500 μs 脉冲时&a…

【火猫】欧洲杯:西班牙老将去卡塔尔淘金,皇马赚麻了

欧洲杯正在如火如荼的进行中,球员的经纪人也在幕后紧罗密布的操作,已经有多位球员将会在新赛季更换门庭。目前正在西班牙国家队征战欧洲杯的老将何塞卢迎来了好消息,根据知名记者罗马诺爆料,何塞卢将会在下赛季加盟卡塔尔球队加拉…

本教程将指导如何通过 Vue 组件和后端 API 交互

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

HarmonyOS开发实战:加密类组件使用方法-API

加密类组件 模块介绍RSA提RSA供生成密钥加解密验签等系列方法(基于HarmonyOS API)AES提供AES生成密钥加解密等系列方法(基于HarmonyOS API)DES提供3DES生成密钥加解密等系列方法(基于HarmonyOS API)SM2提供SM2生成密钥加解密等系列方法(基于HarmonyOS API)SM3提供SM3生成摘要,…

HDFS详细介绍以及HDFS集群环境部署【hadoop组件HDFS笔记】(图片均为学习时截取的)

HDFS详细介绍 HDFS是什么 HDFS是Hadoop三大组件(HDFS、MapReduce、YARN)之一 全称是:Hadoop Distributed File System(Hadoop分布式文件系统);是Hadoop技术栈内提供的分布式数据存储解决方案 可以在多台服务器上构建存储集群&…

42.HOOK引擎核心代码

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

论文阅读:Simple and Efficient Heterogeneous Graph Neural Network

Yang, Xiaocheng, Mingyu Yan, Shirui Pan, Xiaochun Ye and Dongrui Fan. “Simple and Efficient Heterogeneous Graph Neural Network.” AAAI Conference on Artificial Intelligence (2022). 论文地址:[PDF] Simple and Efficient Heterogeneous Graph Neural…