深入理解Java单例模式和优化多线程任务处理

2023-09-18 21:13:01

单例模式能保证某个类在程序中只存在唯一一份实例, 而不会创建出多个实例,并提供一个全局访问点。

饿汉模式

类加载的同时,创建实例。
在这里插入图片描述

class  Singleton {
    private static final Singleton instance = new Singleton();
    //将构造方法设为私有,以防止外部通过new关键字创建新的实例。
    private Singleton() {}
    public static Singleton getInstance() {
        return instance;
    }
}
  • 上述代码定义了一个名为Singleton的类。
  • 在类中定义了一个私有的静态常量instance,它是Singleton类的一个唯一实例。
  • 提供了一个公共的静态方法getInstance(),用于获取Singleton类的唯一实例。

懒汉模式

类加载的时候不创建实例,第一次使用的时候才进行创建。
在这里插入图片描述

单线程版

class Singleton {
    private static Singleton instance = null;
    private Singleton() {
    }
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

多线程版

上述单线程代码在多线程中就会出现错误,多个线程同时调用getInstance()方法时,就可能导致创建出多个实例是不安全的。这里我们只需要在getInstance()方法中添加synchronized关键字就可解决。

class Singleton {
    private static Singleton instance = null;
    private Singleton() {
    }
    public synchronized static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

双重检查锁定

class Singleton {
    //volatile关键字保证了instance变量在多线程环境下的可见性。
    private static volatile Singleton instance = null;
    private Singleton() {}
    public synchronized static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class){
                if (instance == null ){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

双重检查可以这样进行理解:
第一次if先判断实例有没有被创建,如果没被创建就进入第一个if内,使一个线程成功获取锁(其余线程进行阻塞等待),线程获取锁后再次进行判断,判断实例是否创建,没有创建就进行创建。当这个实例创建完了之后,其他竞争到锁的线程就被里层 if 挡住了,也就不会继续创建其他实例。

阻塞队列

阻塞队列能是一种线程安全的数据结构, 并且具有以下特性:

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

阻塞队列的一种典型应用场景就是生产者消费者模型。

在 Java 标准库中内置了阻塞队列。 如果我们需要在一些程序中使用阻塞队列,直接使用标准库中的即可。

  • BlockingQueue 是一个接口,真正实现的类是 LinkedBlockingQueue
  • put 方法用于阻塞式的入队列,take 用于阻塞式的出队列
  • BlockingQueue 也有 offer, poll, peek 等方法, 但这些方法不带有阻塞特性

下面我们来实现一个阻塞队列:

  • 通过循环队列的方式
  • 使用 synchronized 进行加锁控制
public class BlockingQueue {
    private int[] arr = new int[1000];
    private volatile int size = 0;
    private int tail = 0;
    private int head = 0;

    public void put(int value) throws InterruptedException {
        synchronized (this) {
            while (size == arr.length) {
                wait();
            }
            arr[tail] = value;
            tail = (tail + 1) % arr.length;
            size++;
            notifyAll();
        }
    }

    public int take() throws InterruptedException {
        int ret = 0;
        synchronized (this) {
            while (size == 0) {
                wait();
            }
            ret = arr[head];
            head = (head + 1) % arr.length;
            size--;
            notifyAll();
        }
        return ret;
    }

    public static void main(String[] args) throws InterruptedException {
        BlockingQueue bq = new BlockingQueue();
        Thread t1 = new Thread(() -> {

            try {
                for (int i = 0; i < 10; i++) {
                    bq.put(i);
                    System.out.println("生产者放入:" + i);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();
        Thread t2 = new Thread(() -> {

            try {
                for (int i = 0; i < 10; i++) {
                    int num = bq.take();
                    System.out.println("消费者取出:" + num);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t2.start();
        t1.join();
        t2.join();
    }
}

在这里插入图片描述

更多推荐

ubuntu:在ubuntu系统上使用apache2服务器部署多个vue项目

在Ubuntu系统上使用Apache2服务器部署多个Vue.js项目,你可以按照以下步骤进行操作:1.安装Apache2如果你的系统上还没有安装Apache2,可以使用以下命令安装:sudoaptupdatesudoaptinstallapache22.配置虚拟主机要部署多个Vue.js项目,最好为每个项目配置一个单独

算法通关村-----回溯模板如何解决排列组合问题

组合总和问题描述给你一个无重复元素的整数数组candidates和一个目标整数target,找出candidates中可以使数字和为目标数target的所有不同组合,并以列表形式返回。你可以按任意顺序返回这些组合。candidates中的同一个数字可以无限制重复被选取。如果至少一个数字的被选数量不同,则两种组合是不同的

论文阅读:AugGAN: Cross Domain Adaptation with GAN-based Data Augmentation

Abstract基于GAN的图像转换方法存在两个缺陷:保留图像目标和保持图像转换前后的一致性,这导致不能用它生成大量不同域的训练数据。论文提出了一种结构感知(Structure-aware)的图像转换网络(image-to-imagetranslationnetwork)。ProposedFramework为了将图像正

基于复旦微的FMQL45T900全国产化ARM开发开发套件(核心板+底板)

TES745D是我司自主研制的一款基于上海复旦微电子FMQL45T900的全国产化ARM核心板(模块)。该核心板将复旦微的FMQL45T900(与XILINX的XC7Z045-2FFG900I兼容)的最小系统集成在了一个87*117mm的核心板上,可以作为一个核心模块,进行功能性扩展,能够快速的搭建起一个信号平台,方便

在Scrapy框架中使用隧道代理

今天我要和大家分享一些实战经验,教你如何在Scrapy框架中使用隧道代理。如果你是一个热爱网络爬虫的开发者,或者对数据抓取和处理感兴趣,那么这篇文章将帮助你走上更高级的爬虫之路。首先,让我们简单介绍一下Scrapy框架。Scrapy是一个强大的Python网络爬虫框架,它能够帮助我们高效地抓取网页数据并进行处理。使用S

京东商品详情数据采集接口

使用京东商品详情接口的具体流程如下:注册账号并登录。填写应用相关信息,包括应用名称、应用描述、应用回调地址等,然后提交申请。审核通过后,进入应用管理页面,点击“应用信息”,获取应用Key和应用Secret。获取商品详情接口。京东提供了丰富的API接口,不同的接口可以获取不同的商品信息。这里以获取商品详情接口为例。获取A

电容笔哪个厂家的产品比较好?开学季值得买电容笔

现在,几乎每个人都有一个ipad平板,可以帮助你解决很多工作和学习上的难题,比如工作时的整理文档,做一些简单的PPT,以及在学习上记录笔记等等。所以,用一支好用的电容笔来搭配iPad是非常重要的。在这里,我给大家安利几款既使用方便,又价格不贵的电容笔!一、电容笔和ApplePencil的区别以及电容笔的优势1、压感电容

zabbix监控

一、zabbix概述1.zabbix是什么?zabbix是一个基于web界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。zabbix能监视各种网络参数,保证服务器系统的安全运营,并提供灵活的通知机制以让系统管理员快速定位、解决存在的各种问题。zabbix由两部分构成,zabbixserver与可选组件z

【大规模 MIMO 检测】基于ADMM的大型MU-MIMO无穷大范数检测研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。⛳️座右铭:行百里者,半于九十。📋📋📋本文目录如下:🎁🎁🎁目录💥1概述📚2运行结果🎉3参考文献🌈4Matlab代码实现💥1概述针对大型多用户(MU)多输入多输出(MIMO)无线

MATLAB的输入与输出函数

标题输入:input()1.输入单个数值2.输入字符串3.输入以空格隔开的一行数值4.输入以空格与换行符隔开的多行数值输出1.disp()(1)输出单个数值(2)输出一维数组(3)输出矩阵(4)输出字符串2.fprintf()(1)输出格式化的单个数值(2)输出格式化的一维数组(3)输出格式化的矩阵(4)输出格式化的字

PostgreSQL 数据类型

文章目录PostgreSQL数据类型说明PostgreSQL数据类型使用单引号和双引号数据类型转换布尔类型数值类型整型浮点型序列数值的常见操作字符串类型日期类型枚举类型IP类型JSON&JSONB类型复合类型数组类型PostgreSQL数据类型说明PGSQL支持的类型特别丰富,大多数的类型和MySQL都有对应的关系名称

热文推荐