简介
本文是尝试从虚拟机的角度来分析java线程的一些本质
线程模型java的线程模型可以通过下图来说明:
一个对象都有一个相关的锁,每次只能由获得它的一个线程来操作。获得它的线程可以wait,放弃锁,进入等待区域,待被唤醒notify后,它会重新查看锁的状态,参与锁的竞争
查看class文件的汇编代码,可以看到,进入同步区域和退出同步区域分别由两条指令 monitorenter和monitorexit。两者之间的代码块每次只能有一个线程执行
同步分为两种,同步语句和同步方法。同步语句首先得获得synchronized(obj) obj对象的锁,否则,同步语句块内的语句是不会执行的。同步方法是在方法前面加修饰符synchronize。同理,要执行该方法,得闲获取方法所属类的锁(其实是对Class对象上锁)。当同步块语句或者同步方法执行完,无论中间是否有异常,最终都会释放锁
内存模型java内存模型分为主内存和工作内存。每个线程只能操作该工作内存内的数据。两种内存的之间的交互是按照一定协议的,即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的细节。内存模型定义了一下操作
lock:作用于主内存的变量,将它标志为一条线程单独占有
unlock:作用于主内存变量,把处于锁定状态的变量释放,可以被其他线程lock
read:作用于主内存的变量,把一个变量的值从主内存传输到线程的工作内存中,以便接下来的load动作使用
load:作用于工作内存的变量,将上步read的变量放入工作内存的变量副本中
use:作用于工作内存的变量, 将工作内存的变量传递给执行引擎
assign:作用于工作内存的变量,将执行引擎接收到的值赋值给工作内存的变量
store:作用于工作内存的变量,将工作内存的变量传送到主内存
write:作用于工作内存的变量,它把store操作从工作内存得到的变量值放入主内存的变量中
主要有两个作用:
1.保证对该变量的改变是对每个线程可见的(原理是,每次改变后强制同步到主内存,需要一定损耗)。
2.避免指令乱排
1.自旋锁与自适应自旋
简单一点说,两个线程同时竞争一个锁,其中一个获得了,后面那个本来要阻塞的。为了减少阻塞带来的性能损失,让它自旋(忙循环),看看第一个锁是否很快释放锁。忙循环次数如果不是固定的,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定的。就是自适应自旋了
2.锁消除
如果能判断不必要的锁,直接就消除相关锁
3.锁粗化
如果对连续的操作,使用了多个锁,可以同一个范围较大的锁来替换
4.轻量级锁
这个原理比较复杂,涉及到一些特定的锁结构。简单说明,跟传统的锁(重量级)不同,轻量级锁是通过尝试改变一个对象的锁标志位来实现加锁操作的
5.偏向锁
如果去详细了解了上面的轻量级锁,就发现他们原理是差不多的,只不过偏向锁偏向的第一个获得它的线程
1.深入java虚拟机
2.深入理解java虚拟机
更多关于jvm的内容可以继续访问 www.iamcoding.com