JAVA内存模型与线程

是对之前java并发的一个补充。:P

java的操作都是将数据从主内存加载到工作内存去做操作,为了保证线程的安全归定了几个原子性操作。

java的几个原子性操作

  • read:主内存,将数据从主内存传输到工作内存,以便load使用
  • load:工作内存,将read的变量副本放入到工作内存中
  • assign:工作内存,赋值操作。将执行引擎(jvm)中的值赋值给变量。
  • use:工作内存,把工作内存中的值传递给执行引擎。
  • store:工作内存,将数据传输到主内存中,以便write操作使用
  • write:主内存,将数据写入到主内存中。
  • lock:主内存,将变量标识为线程独占
  • unlock:主内存,释放锁标记,标识变量变为共享状态。

几个规定

  • read和load,store和write成对出现,并且先后顺序不能改变
  • assign必须在load之后,且assign之后必须写会主内存,且加载到内存的变量必须assign
  • use、store之前必须assign,load
  • lock操作后工作内存会被清空
  • unlock必须在lock之后,且unlock必须等待变量别写会主内存。

保证线程安全的3个要点

  • 原子性:8个原子操作
  • 可见性:voltile、final、synchrozied可以保证
  • 顺序性:voltile、synchrozied

线程实现

1:1模型:使用内核线程,实现简单,但是无法支持高并发因为内核态和用户态消耗大,并且由于是1:1无法支持高并发。
1:N:使用用户线程,可支持高并发,但是调度等实现难度大。
N:M:用户线程用于并发,内核线程用于调度。综合上面俩种优缺点。

线程状态

new:new一个线程
run:执行start
block:synchronized
wait:没有参数的wait
time_waiting:有参数的wait和sleep

jvm的锁优化

由于锁需要从用户态转到内核态作为控制,所以采用如下几种优化方案。

  • 锁消除:通过逃逸分析发现没有变量逃逸的情况,会去掉锁。
  • 锁粗化:如果多一个对象反复加锁、解锁会考虑合并
  • 偏向锁:如果当前线程获取锁,复制markword,markword修改锁标记位,以及获取锁线程的线程ID;
  • 轻量级锁:如果遇到竞争,复制markword,markword修改锁标记位,以及锁的lockrecord地址。