首页 > 编程语言 >Java并发编程 第七章 共享模型之不可变对象

Java并发编程 第七章 共享模型之不可变对象

时间:2024-09-10 17:53:08浏览次数:12  
标签:Java String int 编程 poolSize value 第七章 new public

1. 不可变对象

@Slf4j(topic = "c.Test1")
public class Test1 {
    public static void main(String[] args) {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                try {
                    log.debug("{}",sdf.parse("1951-04-21"));
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

 

可见线程不安全,加锁可解决但性能太低。换成不可变对象就没问题了。如DateTimeFormatter

package cn.itcast.n7copy;

import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;

/**
 * ClassName: Test1
 * Package: cn.itcast.n7copy
 * Description:
 *
 * @Author: 1043
 * @Create: 2024/9/8 - 20:15
 * @Version: v1.0
 */
@Slf4j(topic = "c.Test1")
public class Test1 {
    public static void main(String[] args) {
        DateTimeFormatter stf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                log.debug("{}", stf.parse("1951-04-21"));
            }).start();
        }
    }

    private static void test() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                synchronized (sdf) {
                    try {
                        log.debug("{}", sdf.parse("1951-04-21"));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

 这次运行没问题了。

2. 不可变设计

final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
    /**
     * The value is used for character storage.
     */
    private final char value[];
    /**
     * Cache the hash code for the string
     */
    private int hash; // Default to 0
// ...
}

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


保护性拷贝
        使用字符串时,也有一些跟修改相关的方法,比如 substring 等,那么下面就看一看这些方法是如何实现的,就以 substring 为例:

public String substring(int beginIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }

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

public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= value.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

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

3. 享元模式

1. 简介

        定义 英文名称:Flyweight pattern. 当需要重用数量有限的同一类对象时
        wikipedia: A flyweight is an object that minimizes memory usage by sharing as much data aspossible with other similar objects
        出自 "Gang of Four" design patterns
        归类 Structual patterns


2. 体现

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

2.2 String 串池
2.3 BigDecimal BigInteger (第六章取款的案例BigDecimal 不能保证线程安全是因为取款涉及操作之间的组合,BigDecimal 只能保证单个操作时线程安全,不能保证多个对象的组合也是线程安全,所以需要原子引用保证)。

3.DIY

设计一个简单的数据库连接池


public class Test3 {
    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.Pool")
class Pool {
    // 1. 连接池大小
    private final int poolSize;

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

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

    // 4. 构造方法初始化
    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));
        }
    }

    // 5. 借连接
    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();
                }
            }
        }
    }

    // 6. 归还连接
    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 {
//太多了,这就省略了
}

先打印wait可能是因为log是比较慢的,这是已经有线程取过连接了。

        以上实现没有考虑:
                连接的动态增长与收缩
                连接保活(可用性检测)
                等待超时处理
                分布式 hash
        对于关系型数据库,有比较成熟的连接池实现,例如c3p0, druid等 对于更通用的对象池,可以考虑使用apache,commons pool,例如redis连接池可以参考jedis中关于连接池的实现。

标签:Java,String,int,编程,poolSize,value,第七章,new,public
From: https://blog.csdn.net/m0_56369671/article/details/142032332

相关文章

  • 基于Java中的SSM框架实现毕业生离校管理系统项目【项目源码+论文说明】
    基于java中的SSM框架实现毕业生离校管理系统演示【内附项目源码+LW说明】课题背景及意义前面介绍到任何行业的改变都在被信息化和科技价值,那么我们此次所介绍的呢,还是基于校园信息化的价值。那么随着校园信息化的不断发展,各种各样的校园信息化软件应运而生,为了满足学生和......
  • JavaWeb案例-登录认证
    在前面的文章中,我们复习了部门管理、员工管理的基本功能。但是我们并没有登录,就直接访问到了Tilias智能辅助系统的后台。这是不安全的,所以今天复习登录认证。最终实现的效果就是用户必须登录之后,才可以访问后台系统中的功能。 1.登录功能 1.1需求在登录界面中,我们可以输......
  • 【pom】解决jar冲突心得 之 通过解决启动报错  Caused by: java.lang.NoClassDefFoun
     解决jar冲突心得之通过解决启动报错 Causedby:java.lang.NoClassDefFoundError:Couldnotinitializeclasscom.fasterxml.jackson.databind.ObjectMapper 学思路 一般情况,出现Causedby:java.lang.NoClassDefFoundError的问题1.要么是jar没有引入pom,所以找不......
  • 基于Java中的SSM框架实现汽车交易系统项目【项目源码+论文说明】计算机毕业设计
    基于java中的SSM框架实现汽车交易系统管理平台演示【内附项目源码+LW说明】摘要电子商务的兴起不仅仅是带来了更多的就业行业。同样也给我们的生活带来了丰富多彩的变化。多姿多彩的世界带来了美好的生活,行业的发展也是形形色色的离不开技术的发展。作为时代进步的发展方......
  • JAVA+VUE实现动态表单配置
    功能描述:资产管理系统中,在资产分类中,给同一种类型的资产配置定制化的表单项,并实现不同类型显示不同的数据,如图所示:数据库设计部分:1.表单项表CREATETABLE`dct_smp`.`t_asset_product_definitions`(`id`bigintNOTNULL,`product_id`bigintNOTNULLCOMMENT'......
  • UEFI原理与编程(一)
    第一章UEFI概述(UnifiedExtensibleFirmwareInterface统一的可扩展固件接口)常见缩写及描述:缩略词全名描述UEFIUnifiedExtensibleFirmwareInterface统一的可扩展固件接口BSBootServices启动服务RTRuntimeService运行时服务BIOSBasicInputO......
  • JavaScript高级——对象
    1、对象的含义:①多个数据的封装体②用来保存多个数据的容器③一个对象代表现实中的一个事物2、为什么要用对象?——统一管理多个数据3、对象的组成①属性:属性名(字符串)和属性值(任意值)组成。代表现实事物的状态数据。②方法:一种特别的属性(属性值是函数)。代表的现......
  • java上传文件接口开发uploadFile
    controller层:@PostMapping("/uploadFile")publicServiceResultuploadFile(MultipartFilefile,@RequestParamStringcompareType){returnprimaryService.uploadFile(file,compareType);}service层:/***样本文件上传*@p......
  • Java Junit单元测试
    文章目录前言一、Junit单元测试---普通Java文件1.Idea依赖导入方式2.Junit的使用二、Junit单元测试---Maven1.普通测试2.单参数测试3.多参数测试三、Junit单元测试---SpringBoot项目1.使用步骤2.@SpringBootTest详解前言所谓单元测试,就是针对最小的功能单......
  • 【JAVA】第四天
    JAVA第四天一、Object类二、Objects类三、包装类四、字符串修改一、Object类表格:方法名作用publicStringtoString()返回对象的字符串表示形式publicbooleanequals(Objecto)判断两个对象是否相等protectedObjectclone​()对象克隆注意toString()和equals(......