java 内存模型与线程
硬件内存模型
java内存模型
主内存vs工作内存
所有变量都在主内存(虚拟机内存的一部分),每条线程都有自己的工作内存,线程所有用到的变量都必须从主内存拷贝出来(不能直接读写主内存变量)
工作内存如何与主内存交互?
8种内存操作:(lock、uncock) (read、load) (use、assign) (store、write)配对出现
volatile关键字
两种特性:1.变量可见性(共享性,自己看法)2.禁止指令重排
可见性:更改变量,虚拟机主内存刷新后所有线程可见
指令重排:volatile boolean flag=false;
…………(其他java语句)
flag=true;
重排后f,lag初始化后立马为true;但volatile 修饰后不会
使用volatile前提条件:
1.运算结果不依赖当前值,或者能够确保只有单一线程修改变量
2.变量不需要其他状态变量参与
volatile关键字在写操作耗时,但是也比锁的总开销小
线程实现
三种方式:内核线程,用户级线程,用户加轻量级进程混合实现
内核线程状态转换开销大,程序一般使用的是内核线程的高级接口——轻量级进程(LWP)
java线程调度
两种方式:协同式线程调度(效果极差),抢占式线程调度(协同分配时间)
java线程定义优先级,实现给某些进程更多时间,但是不太靠谱,java优先级与系统优先级不是一一对应
状态转换
新建-运行-等待-阻塞-结束
java线程安全与锁优化
5类
1.不可变
final关键字修饰的对象、属性
2.绝对线程安全
api实现同步,但是绝对线程安全不是绝对的线程安全
vector get() remove()方法,get(i)同时remove(i),那么,抛出数组越界异常
3.线程相对安全
我们通常说的线程安全,需要保证对象单独的操作是线程安全的,我们调用时不需要额外做保证。但是,特定顺序的连续调用,也可能额外同步手段
4.线程兼容
对象本身不是线程安全,调用端正确使用同步手段保证
5.线程对立
不可能实现多线程安全的代码
线程安全实现方法
1.互斥同步(悲观策略)
互斥方法:临界区 互斥量 信号量
synchronized
2.非阻塞同步(乐观策略)
3.无同步方案
a.可重入代码(返回结果可预测)
b.线程本地储存
锁优化
1.自旋锁与自适应自旋
无法获取锁时,自旋等待一直请求,短时间内可以获得很好收益(避免线程切换开销),自旋次数到达限定次数后,挂起。
2.锁消除
检测到不存在竞争,消除锁(不存在竞争还加锁?api中也有很多锁,比如stringBUffer.append()),stringBUffer.append(s1),stringBUffer.append(s2),stringBUffer.append(s3),三个锁,可以被消除
3.锁粗化
同一个对象反复加锁,那么加锁同步范围扩大,还是上面的stringBUffer.append()),stringBUffer.append(s1),stringBUffer.append(s2),stringBUffer.append(s3),锁粗化后只剩第一个锁。
4.轻量级锁(看书)
5.偏向锁(看书)