设计模式Immutability
1.什么是Immutability
Immutability,不变性,
叫做不变性设计模式,简单来说就是对象一旦创建,状态就不再发生变化。
变量一旦被赋值,就不允许修改了(没有写操作);没有修改操作,就保持了不变性
2.什么情况用Immutablity设计模式
多个线程同时读写同一个共享变量存在并发问题,核心条件是读写,如果只有读,没有写,是没有并发问题的
解决并发问题,最简单的办法就是让共享变量只有读操作,没有写操作。
3.快速实现具备不可变的类
将一个雷的所有属性都设置为final,并且只允许存在只读方法,那么这个类基本上就具备不可变性了。并且这个类本身也是final的,这个类本身不允许继承。
4.jdk中使用Immutablity设计模式的,不可变的类
Long,String
public final class String {
private final char value[];
// 字符替换
String replace(char oldChar,
char newChar) {
//无需替换,直接返回this
if (oldChar == newChar){
return this;
}
int len = value.length;
int i = -1;
/* avoid getfield opcode */
char[] val = value;
//定位到需要替换的字符位置
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
//未找到oldChar,无需替换
if (i >= len) {
return this;
}
//创建一个buf[],这是关键
//用来保存替换后的字符串
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ?
newChar : c;
i++;
}
//创建一个新的字符串返回
//原字符串不会发生任何变化
return new String(buf, true);
}
}
String中的可变方法,往往是新new 出一个新不可变对象来实现,会不会浪费内存呢?会的
5.如何解决内存浪费,使用享元模式
Long,Integer,Short,Byte 等这些基本数据类型的包装类都使用了享元模式
Long使用享元模式的范例(本质上是一个对象池或者缓存池的概念)
Long valueOf(long l) {
final int offset = 128;
// [-128,127]直接的数字做了缓存
if (l >= -128 && l <= 127) {
return LongCache
.cache[(int)l + offset];
}
return new Long(l);
}
//缓存,等价于对象池
//仅缓存[-128,127]直接的数字
static class LongCache {
static final Long cache[]
= new Long[-(-128) + 127 + 1];
static {
for(int i=0; i<cache.length; i++)
cache[i] = new Long(i-128);
}
}
String,Integer类也是类似
6.使用享元模式的这些包装类为什么不适合用于锁?
是因为有些看起来像是私有的锁,其实是共有的
伪代码,看着像是两把锁,其实是同一把锁
class A {
Long al=Long.valueOf(1);
public void setAX(){
synchronized (al) {
//省略代码无数
}
}
}
class B {
Long bl=Long.valueOf(1);
public void setBY(){
synchronized (bl) {
//省略代码无数
}
}
}
7.Immutability模式注意事项
- 对象的所有属性都是final的,并不能保证不可变性
- 不可变对象也需要正确发布
final修饰的普通对象,对象属性是可以被修改的
8.正确使用Immutability的姿势
public final class ServerConfig {
private final int masterExecThreads = 100;
private final int masterExecTaskNum = 20;
private final int listenPort = 5678;
private final String address = NetUtils.getAddr(listenPort);
public String getAddress() {
return address;
}
public int getMasterExecThreads() {
return masterExecThreads;
}
public int getMasterExecTaskNum() {
return masterExecTaskNum;
}
public int getListenPort() {
return listenPort;
}
}
设计模式Immutability的更多相关文章
- 作为一名双非本科毕业的Java程序员,我该如何在日益严重的内卷化中避免被裁?
前言 对一个 Java 程序员而言,并发编程能否熟练掌握是判断他是不是优秀的重要标准之一.因为并发编程在 Java 语言中最为晦涩的知识点,它涉及内存.CPU.操作系统.编程语言等多方面的基础能力,更 ...
- 并发设计模式:Immutability模式
多个线程同时读写同一共享变量存在并发问题,其中的必要条件之一就是 读写 ,如果没有写,只存在读,是不会存在并发问题的. 如果让一个共享变量只有读操作,没有写操作,如此则可以解决并发问题.该理论的具体实 ...
- 设计模式之构建者模式(Builder):初步理解
构建者(Builder)设计模式(又叫生成器设计模式): 当一个类的内部数据过于复杂的时候(通常是负责持有数据的类,比如Config.VO.PO.Entity...),要创建的话可能就需要了解这个类的 ...
- MVVM设计模式和WPF中的实现(四)事件绑定
MVVM设计模式和在WPF中的实现(四) 事件绑定 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在WPF中 ...
- java EE设计模式简介
1.何为设计模式 设计模式提供了对常见应用设计问题的解决方案.在面向对象的编程中,设计模式通常在解决与对象创建和交互相关的问题,而非整体软件架构所面对的大规模问题,它们以样板代码的形式提供了通用的解决 ...
- 计算机程序的思维逻辑 (54) - 剖析Collections - 设计模式
上节我们提到,类Collections中大概有两类功能,第一类是对容器接口对象进行操作,第二类是返回一个容器接口对象,上节我们介绍了第一类,本节我们介绍第二类. 第二类方法大概可以分为两组: 接受其他 ...
- 《JavaScript设计模式 张》整理
最近在研读另外一本关于设计模式的书<JavaScript设计模式>,这本书中描述了更多的设计模式. 一.创建型设计模式 包括简单工厂.工厂方法.抽象工厂.建造者.原型和单例模式. 1)简单 ...
- 《JavaScript设计模式与开发实践》整理
最近在研读一本书<JavaScript设计模式与开发实践>,进阶用的. 一.高阶函数 高阶函数是指至少满足下列条件之一的函数. 1. 函数可以作为参数被传递. 2. 函数可以作为返回值输出 ...
- 设计模式之行为类模式大PK
行为类模式大PK 行为类模式包括责任链模式.命令模式.解释器模式.迭代器模式.中介者模式.备忘录模式.观察者模式.状态模式.策略 ...
随机推荐
- 解决小程序中Data.parse()获取时间戳IOS不兼容
由于与后台接口必须对比时间戳所以首先得前台获取时间戳.刚开始是获取手机本地时间,但用户改了时间就废了..... 后来就从服务器上获取个时间再转换为时间戳(是不是很操蛋,先从服务器上获取在TM的自己比较 ...
- 【pytest系列】- pytest测试框架介绍与运行
如果想从头学起pytest,可以去看看这个系列的文章! https://www.cnblogs.com/miki-peng/category/1960108.html 前言 目前有两种纯测试的测 ...
- php 获取某年后的日期
比如两年后:date('Y-m-d',strtotime('+2 year')) 月份year改成month
- HashMap实现原理一步一步分析(1-put方法源码整体过程)
各位同学大家好, 今天给大家分享一下HashMap内部的实现原理, 这一块也是在面试过程当中基础部分被问得比较多的一部分. 想要搞清楚HashMap内部的实现原理,我们需要先对一些基本的概念有一些了解 ...
- 混部之殇-论云原生资源隔离技术之CPU隔离(一)
作者 蒋彪,腾讯云高级工程师,10+年专注于操作系统相关技术,Linux内核资深发烧友.目前负责腾讯云原生OS的研发,以及OS/虚拟化的性能优化工作. 导语 混部,通常指在离线混部(也有离在线混部之说 ...
- 一文带你详细介绍c++中的std::move函数
前言 在探讨c++11中的Move函数前,先介绍两个概念(左值和右值) 左值和右值 首先区分左值和右值 左值是表达式结束后依然存在的持久对象(代表一个在内存中占有确定位置的对象) 右值是表达式结束时不 ...
- Ubuntu部署项目
一.Ubuntu目录结构 目录 说明 bin 存放二进制可执行文件(ls,cat,mkdir等) .exe== boot 存放用于系统引导时使用的各种文件 开机引导 dev 用于存放设备文件 打印机啥 ...
- 线程本地存储(动态TLS和静态TLS)
线程本地存储(TLS) 对于多线程应用程序,如果线程过于依赖全局变量和静态局部变量就会产生线程安全问题.也就是一个线程的使用全局变量可能会影响到其他也使用此全局变量的线程,有可能会造成一定的错误,这可 ...
- 如何更好理解Peterson算法?
如何更好理解Peterson算法? 1 Peterson算法提出的背景 在我们讲述Peterson算法之间,我们先了解一下Peterson算法提出前的背景(即:在这个算法提出之前,前人们都做了哪些工作 ...
- c语言常见编译问题
1 . warn.c:6:2: warning: implicit declaration of function 'strcpy' [-Wimplicit-function-declaration] ...