哈哈、话说真是种瓜得瓜,种豆得豆;有付出就总会有收获;今天老大分享会上刚好说到Java多线程中单例的使用问题;自己这几天刚好看到这些内容、所以在会上把自己所知道的秀了一把。
晚上去游泳了、游泳馆里摸着自己的赘肉,哎、那叫一个感叹啊;太久不运动、果然还是容易肥起来啊;然后游泳池里拼命游、最后游了1.5公里,离自己设定的目标两公里还是有点距离。以后看来还是要都运动才行啊、年轻人,毕竟还没结婚呢。
说第三章内容吧、这章内容较多,但也是重点、下面开始看黑板
线程安全问题的产生:多个线程并发访问共享变量、共享资源
为保障安全性,将多线程对数据的并发访问转换为串行访问,锁便应运而生
锁的持有线程在其获得锁之后和释放之前这段时间内所执行的代码被称为临界区
按Java虚拟机对锁的实现方式划分:
内部锁(synchronized)、非公平锁
显示锁(Lock接口的实现类ReentrantLock)、支持公平锁和非公平锁
锁通过互斥(一个锁一次只能被一个线程持有)保证原子性
锁的获得隐含着刷新处理器缓存这个动作,使得读线程在执行临界区代码前,将写线程可以对共享变量所做的更新同步到该线程执行处理器的高速缓存中;
而锁的释放隐含着冲刷处理器缓存这个动作,使得写线程对共享变量所做的更新能够被一个线程访问;由此保证可见性
锁保证有序性:在临界区所执行的一系列代码看起来像完全按照源代码顺序执行的
与锁相关的几个概念:
1、 可重入性:一个线程在其持有一个锁时能否再次申请该锁,能则为可重入的,否则为非可重入的
2、 锁的争用与调用:公平锁、非公平锁
3、 锁的粒度:一个锁实例所保护的共享数据的数量大小就称为该锁的粒度
锁的开销及可能导致的问题:
处理器时间开销:锁的申请和释放、上下文切换
锁泄露:该锁一直无法被释放而导致其他线程一直无法获得该锁的现象
线程同步机制的底层助手:内存屏障
定义:是对一类仅针对内存读、写操作指令的跨处理器架构的比较底层的抽象
插入到两指令间进行使用,其作用是禁止编译器、处理器重排序从而保障有序性
按可见性划分:加载屏障(刷新处理器缓存)、存储屏障(冲刷处理器缓存)
按有序性划分:获取屏障(读操作之后插入该屏障,禁止该读操作与其后的任何读写操作之间进行重排序)、释放屏障(写操作之前插入该屏障,禁止该写操作与其前的任何读写操作之间进行重排序)
轻量级同步机制:volatile关键字
表示被修饰的变量的值容易变化,这意味着对这种变量的读写操作都必须从高速缓存或者主内存中读取,以读取变量的相对新值;所以volatile变量不会被编译器分配到寄存器进行存储;对volatile变量的读写操作都是内存访问操作
CAS与原子操作:
Compare and swap 是对一种处理器指令的称呼
CAS 作为代理人,相当于如下伪代码:
Boolean compareAndSwap(variable v, objecta, object b){
f(a == v.get()){//check:检查变量是否被其他线程修改过
v.set(b);//act:更新变量值
return true;
}
return false;//变量值已被其他线程修改,更新失败
}
原子操作工具:原子变量类(Atomics)是基于CAS实现的能够保障对共享变量进行read-modify-write更新操作的原子性和可见性的一组工具类
|
分组 |
类 |
||
|
基础数据型 |
AtomicInteger、AtomicLong、AtomicBoolean |
||
|
数组型 |
AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray |
||
|
字段更新器 |
AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater |
||
|
应用型 |
AtomicReference、AtomicStampedReference、AtomicMarkableReference |
||
对象的初始化安全:重访final与static
java中类的初始化实际上采取了延迟加载技术、即一个类被Java虚拟机加载之后,该类的所有静态变量值都仍然是其默认值,直到有个线程初次访问了该类的任意一个静态变量才使得这个类被初始化
static关键字仅仅保障读线程能够读取到相应字段的初始值,而不是相对新值
final关键字所修饰的字段都是初始化完毕的,其他线程读取这些字段的时候所读取到的值都是相应字段的初始值