JUC6-共享模型之不可变

news2024/9/21 0:30:39

目录

日期转换的问题

问题提出

思路:同步锁

思路:不可变

不可变设计

final的使用

保护性拷贝

享元模式

概述

体现

包装类

String串池

BigDecimal BigInteger

DIY

原理:final

无状态


日期转换的问题

问题提出

下面的代码在运行时,由于 SimpleDateFormat 不是线程安全的,有很大几率出现java.lang.NumberFormatException 或者出现不正确的日期解析结果

思路:同步锁

能解决问题,但带来的是性能上的损失,并不算很好

思路:不可变

如果一个对象在不能够修改其内部状态(属性),那么它就是线程安全的,因为不存在并发修改

这样的对象在 Java 中有很多,例如在 Java 8 后,提供了一个新的日期格式化类DateTimeFormatter:

DateTimeFormatter stf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
for (int i = 0; i < 10; i++) {
      new Thread(() -> {
           TemporalAccessor parse = stf.parse("1951-04-21");
           log.debug("{}", parse);
      }).start();
}

不可变设计

String 类也是不可变的,以它为例,说明一下不可变设计的要素

final的使用

该类、类中所有属性都是 final 的

  • 属性用 final 修饰保证了该属性是只读的,不能修改
  • 类用 final 修饰保证了该类中的方法不能被覆盖,防止子类无意间破坏不可变性

保护性拷贝

以 substring 为例:

内部是调用 String 的构造方法创建了一个新字符串,再进入这个构造看看,是否对 final char[] value 做出了修改:  

结果也没有,构造新字符串对象时,会生成新的 char[] value,对内容进行复制,这种通过创建副本对象来避免共享的手段称之为保护性拷贝(defensive copy)

享元模式

概述

英文名称:Flyweight pattern,当需要重用数量有限的同一类对象时

出自 "Gang of Four" design patterns

归类 Structual patterns

体现

包装类

在JDK中 Boolean,Byte,Short,Integer,Long,Character 等包装类提供了 valueOf 方法,例如 Long 的 valueOf 会缓存 -128~127 之间的 Long 对象,在这个范围之间会重用对象,大于这个范围,才会新建 Long 对象:

注意:

  • Byte, Short, Long 缓存的范围都是 -128~127
  • Character 缓存的范围是 0~127
  • Integer的默认范围是 -128~127,最小值不能变,但最大值可以通过调整虚拟机参数-Djava.lang.Integer.IntegerCache.high来改变
  • Boolean 缓存了 TRUE 和 FALSE
String串池
BigDecimal BigInteger

DIY

例如:一个线上商城应用,QPS 达到数千,如果每次都重新创建和关闭数据库连接,性能会受到极大影响。 这时预先创建好一批连接,放入连接池。一次请求到达后,从连接池获取连接,使用完毕后再还回连接池,这样既节约了连接的创建和关闭时间,也实现了连接的重用,不至于让庞大的连接数压垮数据库

import lombok.extern.slf4j.Slf4j;

import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicIntegerArray;

@Slf4j(topic = "c.Test43")
public class Test43 {
    public static void main(String[] args) {
        Pool pool = new Pool(2);
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                Connection conn = pool.borrow();
                try {
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                pool.free(conn);
            }).start();
        }
    }
}
@Slf4j(topic = "c.Test43")
class Pool{
    //1.连接池大小
    private final int poolSize;

    //2.连接对象数组
    private Connection[] connections;

    //3.连接状态数组 0:空闲   1:繁忙
    private AtomicIntegerArray states;

    public Pool(int poolSize) {
        this.poolSize = poolSize;
        this.connections = new Connection[poolSize];
        this.states = new AtomicIntegerArray(new int[poolSize]);
        for (int i = 0; i < poolSize; i++) {
            connections[i] = new MockConnection("连接" + (i+1));
        }
    }

    //借连接
    public Connection borrow(){
        while (true){
            for (int i = 0; i < poolSize; i++) {
                //获取空闲连接
                if (states.get(i) == 0) {
                    if (states.compareAndSet(i,0,1)) {
                        log.debug("borrow {}",connections[i]);
                        return connections[i];
                    }
                }
                //没有空闲连接,当前线程进入等待
                synchronized (this){
                    try {
                        log.debug("wait...");
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    //归还连接
    public void free(Connection conn){
        for (int i = 0; i < poolSize; i++) {
            if (connections[i] == conn) {
                states.set(i,0);
                synchronized (this){
                    log.debug("free {}",conn);
                    this.notifyAll();
                }
                break;
            }
        }
    }
}

class MockConnection implements Connection{
    private String name;

    public MockConnection(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "MockConnection{" +
                "name='" + name + '\'' +
                '}';
    }

}

以上实现没有考虑:

  • 连接的动态增长与收缩
  • 连接保活(可用性检测)
  • 等待超时处理
  • 分布式 hash

原理:final

字节码:

final 变量的赋值也会通过 putfield 指令来完成,同样在这条指令之后也会加入写屏障,保证在其他线程读到它的值时不会出现为 0 的情况

无状态

在 web 中,设计 Servlet 时为了保证其线程安全,不为 Servlet 设置成员变量,这种没有任何成员变量的类是线程安全的,因为成员变量保存的数据也可以称为状态信息,因此没有成员变量就称之为无状态

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

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

相关文章

python井字棋游戏设计与实现

python实现井字棋游戏 游戏规则&#xff0c;有三个井字棋盘&#xff0c;看谁连成的直线棋盘多谁就获胜 棋盘的展现形式为 棋盘号ABC和位置数字1-9 输入A1 代表在A棋盘1号位数下棋 效果图如下 部分源码如下&#xff1a; 卫星工纵浩 白龙码程序设计&#xff0c;点 代码获取 …

Stability AI发布了单目视频转4D模型的新AI模型:Stable Video 4D

开放生成式人工智能初创公司Stability AI在3月发布了Stable Video 3D&#xff0c;是一款可以根据图像中的物体生成出可旋转的3D模型视频工具。Stability AI在7月24日发布了新一代的Stable Video 4D&#xff0c;增添了赋予3D模移动作的功能。 Stable Video 4D能在约40秒内生成8…

DBAPI如何用SQL将多表关联查询出树状结构数据(嵌套JSON格式)

场景描述 假设数据库中有3张表如下&#xff1a; 客户信息表 订单表 订单详情表 一个客户有多个订单&#xff0c;一个订单包含多个产品信息&#xff0c;客户-订单-产品就构成了3级的树状结构&#xff0c;如何查询出如下树状结构数据呢&#xff1f; [{"customer_age"…

矩阵--旋转图像

给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 &#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&a…

嵌入式Day33---Linux软件编程---网络编程

目录 一、TCP包头 1.1.源端口 1.2.目的端口 1.3.序号 1.4.确认号 1.5.数据偏移 1.6.保留 1.7.指令信号 1.SYN 2.ACK 3.FIN 4.RST 5.PSH 6.URG 1.8.窗口 1.9.校验和 1.10.紧急指针 二、TCP的过程 2.1三次握手 2.2.传输数据 ​编辑 2.3.四次挥手 ​编辑 …

SpringBoot依赖之Spring Data Redis 一 List 类型

概念 Spring Data Redis (AccessDriver) 依赖名称: Spring Data Redis (AccessDriver)功能描述: Advanced and thread-safe Java Redis client for synchronous, asynchronous, and reactive usage. Supports Cluster, Sentinel, Pipelining, Auto-Reconnect, Codecs and muc…

[Qt][QSS][下]详细讲解

目录 1.样式属性0.前言1.盒模型(Box Model) 2.常用控件样式属性1.按钮2.复选框3.单选框4.输入框5.列表6.菜单栏7.注意 1.样式属性 0.前言 QSS中的样式属性⾮常多&#xff0c;不需要都记住&#xff0c;核⼼原则是⽤到了就去查 ⼤部分的属性和CSS是⾮常相似的 QSS中有些属性&am…

Linux CentOS手动安装Node.js(图文教程)

本章教程主要介绍如何在centos7上安装指定版本的Node.js 一、下载nodejs 前往Node.js官网&#xff0c;根据自己需要安装的版本进行下载。 官网下载地址&#xff1a;https://nodejs.org/zh-cn/download/prebuilt-binaries 本文&#xff0c;以v14.21.3版本介绍整个安装过程。 二、…

<STC32G12K128入门第十步>USB HID键盘

前言 最近公司的一款低功耗的遥控器涉及到使用USB HID的功能,就是需要将BLE蓝牙读取的IC卡的数据在通过USB接口上传到电脑的记事本上面。 一、USB HID是啥? USB HID类是USB设备的一个标准设备类,包括的设备非常多。HID类设备定义它属于人机交互操作的设备,用于控制计算机…

IDEA 导入 RocketMQ 源码

目录 前言一、RocketMQ 架构二、环境准备三、下载源码四、编译源码4.1 导入源码4.2 目录结构4.3 运行程序1. 启动 Namesrv2. 启动 Broker3. 启动 Producer4. 启动 Consumer 五、监控平台的搭建5.1 下载 console 源码5.2 IDEA 启动 前言 最近项目中有个功能需要在本地调试下 Ro…

SAM2论文核心速览

官方博客&#xff1a; https://ai.meta.com/blog/segment-anything-2/ 官方论文&#xff1a;​​​​​​https://ai.meta.com/research/publications/sam-2-segment-anything-in-images-and-videos/ 一、研究背景 研究问题&#xff1a;这篇文章要解决的问题是如何在图像和视频…

公式编辑器 -vue-formula-editor

前言 公式编辑旨在帮助用户使用可视化的前提&#xff0c;能便捷的使用平台&#xff0c;例如低代码平台使用广泛 vue-formula-editor vue-formula-editor是一款开源的Vue公式计算组件&#xff0c;可以帮助开发者快速集成公式编辑 在线体验 demo & 源码 安装 npm i vue-form…

CentOS 上安装 Java 17

要在 CentOS 上安装 Java 17&#xff0c;您可以使用多种方法。这里我将向您展示如何通过下载 Oracle 提供的 Java 开发工具包 (JDK) 或使用其他开源 JDK 版本&#xff08;如 Adoptium 或 OpenJDK&#xff09;来完成安装。 方法一&#xff1a;使用 Oracle JDK 17 下载 JDK 17&a…

HTB-BoardLight靶机笔记

BoardLight靶机笔记 概述 HTB的靶机BoardLight 靶机地址&#xff1a;https://app.hackthebox.com/machines/BoardLight 一、nmap扫描 1&#xff09;端口扫描 -sT tcp全连接扫描 --min-rate 以最低速率10000扫描 -p- 扫描全端口 sudo nmap -sT --min-rate 10000 -p- -o p…

【论文写作】怎么写一篇学术论文

文章目录 &#xff08;一&#xff09;非匀速地写论文&#xff08;二&#xff09;弄清期刊的投稿要求以及使用论文模板&#xff08;三&#xff09;论文各个部分撰写的顺序&#xff08;四&#xff09;图表比你想象中的要重要许多&#xff08;五&#xff09;结果和讨论&#xff08…

Java | Leetcode Java题解之第349题两个数组的交集

题目&#xff1a; 题解&#xff1a; class Solution {public int[] intersection(int[] nums1, int[] nums2) {Arrays.sort(nums1);Arrays.sort(nums2);int length1 nums1.length, length2 nums2.length;int[] intersection new int[length1 length2];int index 0, index…

CPU占用异常分析

文章目录 问题现象二次排查参考资料 问题现象 执行文件解压&#xff0c;执行过程中被kill掉了&#xff0c;两次均如此。 [rootlocalhost demo_2]# gzip -d demo.sql.gz Killed网上查资料&#xff0c;可能是磁盘不足、系统资源不足&#xff1b; 磁盘查看没有问题&#xff0c;内…

Matlab2021b通过CNN、CNN-LSTM模型实现对声音信号的二分类与四分类

1、利用Matlab2021b训练CNN、CNN-LSTM模型&#xff0c;对采集的一维时序信号进行分类二分类与四分类 2. 声音信号每个样本数据长度3001个采样点&#xff0c;对其进行归一化处理 3、CNN时序信号多分类执行结果截图 3.1 二分类&#xff1a; CNN模型&#xff1a; 训练集损失值…

Linux装ifort环境

下载完成之后&#xff0c;需要解压文件 t tar zxvf IPSXE2020u4Linux.tgz 解压完成之后进入文件夹&#xff0c;我们使用GUI界面安装。 键入./install_GUI.sh 启动安装程序 收集用户信息&#xff0c;选择同意或者不同意都可以 这一步需要等待十几秒 核验不通过 这是缺少运行程…

牛客JS题(四十五)数组去重

注释很详细&#xff0c;直接上代码 涉及知识点&#xff1a; set的灵活用法去除的判别标准 题干&#xff1a; 我的答案 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><style>/* 填写样式 */</style></head><bo…