并发编程基本设计方案 线程本地存储模式(没有共享,就没有伤害)


上篇我们提到,并发编程中,并发问题之所以会产生,是因为多个线程对一个资源进行读写操作,即共享 + 读写,在上篇中,我们了解到不可变模式通过破坏读写这个条件,避免的并发问题的产生,那么今天我们要讲的是通过限制共享,来避免并发问题的产生。


在讲之前,我们先来补一补JVM的知识,我们知道JVM有三大子系统,类加载器,字节码执行引擎,以及运行时数据区,而今天我们来了解一下运行时数据区,我们从线程的视角来看看运行时数据区究竟有什么?在线程的眼中,运行时数据区,可以被分为两块区域,一块是我自己独享的,一块是我和其他线程共享的,独享的区域包括 虚拟机栈,本地方法栈,程序计数器,共享的区域包括 方法区(元数据区)堆内存。简单介绍一下这些区域的作用,方法的调用需要借助栈这种数据结构,Java这门编程语言是可以借助一些机制调用本地方法,就是Native Method,就是用C、C++写的函数,于是栈就被分为了两个,虚拟机栈主要就是用于维护Java方法的调用关系,而本地方法栈就是维护Native Method的调用关系,程序计数器就是记录当前执行到整个流程中的哪一步了。方法区(元数据区)记录了类的元信息,比如类的名字,类的字段,类的方法,堆内存就是存储对象实例的地方。


好,知识补充到此为止,到此,你已经知道了,一个线程的创建,必然会伴随着虚拟机栈,本地方法栈以及程序计数器的分配,而并发问题产生的一个条件就是,多个线程在共享一块数据,就是同一块内存区域,那么今天所说的限制共享,就是将数据移动到线程的独享区中,这样其他线程就无法访问了,从而避免的并发问题的产生。线程是执行方法的直接载体,将数据移动到线程的独享区,对应到代码中,就是将数据移入到局部变量中,这样其他线程就访问不到,限制了共享。但是这种方法存在比较严重的问题,那就是对象的重复创建,比如,有10个线程,调用A方法3次,A方法中利用局部变量保存一个对象,随着线程的执行,对象就是被重复创建,创建的个数与调用次数成正比,这对于JVM来说,是难以接受的。于是我们可以放开一点限制,数据不一定要保存在局部变量中,我们的核心目的是在线程层面,数据独享,为了达到这个目的,Java给我们提供了一个ThreadLocal ,这个工具类可以帮我们把数据维护成线程独享。但是值得注意的是,ThreadLocal仅仅只是一个工具类,并不负责数据的持有,真正持有数据的其实是Thread


public T get() {
//这里就可以证明,数据其实是被Thread持有
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}

ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}


对于ThreadLocal具体怎么用,网上已经有很多教程了,你也可以尝试看看源码,至于ThreadLocal的缺点,我们下期来简单聊聊。


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