多线程关键字
synchronized关键字
synchronized能使代码块或者方法同步,synchronized修饰的代码块或者方法具有原子性
使用方法
- 修饰代码块,作用于代码块,锁的传入对象的锁
sychronized (obj) {
for (int i = 0; i < 100; i++)
System.out.println(i)
}
原理:synchronized 同步语句块的实现使用的是 monitorenter 和 monitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。 当执行 monitorenter 指令时,线程试图获取锁也就是获取 monitor(monitor对象存在于每个Java对象的对象头中,synchronized 锁便是通过这种方式获取锁的,也是为什么Java中任意对象可以作为锁的原因) 的持有权.当计数器为0则可以成功获取,获取后将锁计数器设为1也就是加1。相应的在执行 monitorexit 指令后,将锁计数器设为0,表明锁被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外一个线程释放为止。
-
修饰方法,作用于整个方法,锁的是本对象
原理:synchronized 修饰的方法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是 ACC_SYNCHRONIZED 标识,该标识指明了该方法是一个同步方法,JVM 通过该 ACC_SYNCHRONIZED 访问标志来辨别一个方法是否声明为同步方法,从而执行相应的同步调用。 -
修饰静态方法,作用于整个静态方法,锁的是所有该类的对象
-
修饰类,作用于类的所有方法,锁所有 对象
volatile关键字
- volatile关键修饰的变量最大的作用是每次线程读取的该值都是最新的
- 使JVM每次要用到该变量都到主内存中读取
- 禁止变量操作重排序(双重校验实现单例模式)
- volatile关键字并不具有原子性
比如两个线程同时读取volatile修饰的变量i时,读到i的最新值都是5,然后两个线程对i进行自增,自增后i的值是6,但理论应该是7