并发编程常见设计方案 不可变模式


并发问题的产生的原因最核心的原因就是 共享 + 读写,如果一个变量被共享,而且还有多个线程对其进行读写,那么就一定会发生并发问题。我们解决问题的思路有两种,一种是根据问题的特点制定相关的解决方案,另外一种是不让问题产生。并发问题的出现一定是,有些线程对共享变量进行读操作,有些线程对同一共享变量进行写操作。就像解决死锁问题一样,破坏死锁的条件就能解决死锁问题,那么如果我们破坏产生并发问题的条件,那么也可以避免并发产生的问题,而今天要介绍的并发设计方案:不可变模式 破坏的就是读写条件,如果多个线程只读的话,就不会有并发问题,简单来说,就是对象一旦被创建之后,就不可被修改,始终保持着初始状态。对应到Java代码中,就是类+final, 类中的属性+final 并只提供可读方法, 在Java中有很多类都是这样的设计,比如基本数据类型的包装类(Long,Integer)还有肯定会使用的String类,这些类的设计都遵守不可变模式,

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];

上面是Java8的代码,可以看到String类的设计符合不可变模式,但是不可变模式不是不能有写操作的方法吗?String类可是有replace()的呀,其实不可变模式的核心只要保证对象的状态从创建开始一直到程序结束都不改变就可以了。如果你看过 replace()的源码,就知道他其实返回的是一个新的String对象

public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
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);
}
}
return this;
}

但是不可变模式也是有缺点的,那就是会大量创建对象,导致内存的浪费,于是我们可以通过享元模式,将相同的对象缓存起来,当要继续创建相同的对象时,就不在创建,而是从缓存池中取出来就好了,Java中的基本数据类型包装类就是这样设计的,比如Long类型就会提前缓存[-128,127]的数。

public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}

String也会做缓存,只是缓存的都是String的字面量,即写死在代码里的字符串值,比如 String s = “pandaer” “pandaer”就是字面量,他就会被缓存到字符串常量池中,如果后面在代码中还出现“pandaer”的时候用的就是字符串常量池中的同一个对象。


0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
pandaer
作者分享
你是否也只把 MySQL 当作一个“只会存取数据”的黑盒?前端发请求,你查数据库,看似简单,但当查询变慢、死锁频发时,你是否因为不懂内部原理而无从下手? 本文不讲晦涩的源码,而是像拆解玩具一样,带你钻进 MySQL 内部:从连接器到存储引擎,看清一条 SQL 到底经历了什么;从 Redo Log 到两阶段提交,搞懂数据是如何被安全写入的。别再只做“CRUD”工程师了,今天带你真正看透 MySQL 的本质! 原文如下:https://mp.weixin.qq.com/s/f6loMKH25VWPfkJYl2yAxg
5
  不知道你有没有想过,计算机是如何从一个想法不断演进到今天的呢?   在起初有这样一个想法,“计算”这件事能不能用机器来实现,让机器来帮我们干活呢?这个想法诞生之后,就不断的有人还在开始尝试实现这个想法,其中图灵提出了自己的一个实现思路,也就是现在大名鼎鼎的「图灵机」,但是图灵机仍然无法落地,因为它有一个「无限长纸带」的假设。于是后人在图灵机这个理想的模型上继续演进,其中冯洛伊曼提出的计算机体系结构成为了主流。   在冯洛伊曼体系结构中,计算机所有的一切都由01组成,无论是文本,图片,声音,还是指令;有5大基础组件,运算器,控制器,存储器,输入输出。后人基于冯洛伊曼提出的计算机体系结构,结合数学和物理相关的知识,就制造出了那些我们耳熟能详的计算机硬件,比如CPU,内存,硬盘,各种外设。基于这些计算机硬件我们就可以组装出一台可以运行的计算机了。值得一提的是,在制造计算机硬件的过程中,数学与物理电学相关的部分,衍生出了一个新的学科「数字逻辑」。   到此,一个可运行的计算机就被制造出来了。
5
  MySQL数据页笔记 这种底层数据结构的设计,基本上都有两部分组成,一部分是真实的数据,一部分是描述这些数据的信息,也叫做元信息。   数据页的组成分为这么几个部分   1. file header 校验和 页号 前一条页号 下一条页号   2. page header 下一条记录 删除标识   3. 最大最小记录   4. record data   5. free space   6. page directory slot 二分查找   7. file tail 校验和 与file header一起用作刷盘时数据的完整性校验。
2
  精力拥有四大来源,这四大来源组成了精力金字塔,从底往上分别是体能,情绪,专注,目标意义感。   体能是基础,体能好,尤其是心肺能力好的人,更加不容易疲劳。所以有规律的运动很重要。   情绪,消极的情绪会不断消耗自己的精力,相信你一定深有感受,遇到消极情绪,需要及时走出来,我的做法就是不纠结,不去想。所以保持一个正面的,积极的心情也很重要   专注,指的是专注的思维,是我们常说的专注力,人脑天生对有难度复杂的事情有抗拒感,而且我们一段时间就只能做一件事情   目标意义感,就是要有清晰的目标,明确的计划。
3
  精力是什么? 如果把人比做手机,那么精力就是「电池」,精力决定了你一天可以做多少事情,效率又有多高。精力充沛的人效率高,做事又好又快,而精力低的人不仅效率低,而且完成的事情的质量也不高。所以让我们做一个高精力的人吧!   那么怎样才算是高精力的人?我将精力划分为4个等级,「不堪重负」「积极应对」「全力以赴」「游刃有余」   1. 不堪重负:不仅自己有挫败感,而且还终日疲惫不堪   2. 积极应对:白天的工作可以认真完成,但是一下班,就想睡觉,甚至连娱乐都不想   3. 全力以赴:白天可以认真工作,下班后至少不会只想躺在床上   4. 游刃有余:白天不仅可以认真工作,下班后也可以积极享受生活,或者充电学习   精力除了有这4个等级之外,精力在一天也是波动的,某个时间段精力高,某个时间段精力低。一个可以落地的方法是**在精力高的时候做有难度高专注的事情,做重要的事情**,那如何判断自己的那个时间段精力高呢?自测,将一天分为几个时间段   1. 醒来后两个小时   2. 8~11点   3. 11~13点   4. 13点~15点   5. 15点~18点   6. 18点~20点   7. 20点~23点   在你认为精力最好的时间段打10分,然后再给其他时间段基于此打分,得到一个曲线图。然后在这个曲线图的高点做重要的事情,低点做一些不费脑子的事情。
5
下载 APP