© 2020 GitHub, Inc.

synchronized

in Note with 2 comments

synchronized

使用

// 锁的是当前实例对象
public synchronized void method() {
  // 加锁代码块
}
// 锁的是当前class对象
public static synchronized void method() {
  // 加锁代码块
}
// 锁的是括号里的对象
// 1.锁的是实例对象
public void method() {
  synchronized (this) {
    // 加锁代码块
  }
}
// 2.锁的是class对象
public void method() {
  synchronized (this.getClass()) {
    // 加锁代码块
  }
}
// 3.锁具体对象
class Demo {
  private Object lock = new Object();
  public void method() {
    synchronized (lock) {
      // 加锁代码块
    } 
  }
}

锁的四种状态

Java6之后引入了”偏向锁“和”轻量级锁“,之前只有”无锁“和”重量级锁“。级别由低到高为:

无锁->偏向锁->轻量级锁->重量级锁

无锁

即不对资源做限制,所有线程都可以直接访问。

偏向锁

偏向锁会记录线程的ID,当没有新的线程来访问的时候,就不会做同步操作,提升性能。

假设现在锁的Mark Word(用于存储对象的hashCode和锁信息)中的线程ID属于A,当线程B来访问的时候,会将线程B的ID与当前记录的ID比较,会有一下几种情况:

相同:不做CAS来加锁和解锁;

不相同:使用CAS来替换Mark Word中的线程ID。1、成功则代表线程A已经结束,更新Mark Word的线程ID,锁不升级;2、不成功则代表要竞争资源,升级锁为轻量级锁,按照轻量级锁的方式竞争锁。

轻量级锁

新的线程进来,发现是轻量级锁的时候,会讲Mark Word复制到该线程的栈帧中,然后采用CAS操作尝试替换Mark Word为指向锁记录的指针,会有以下情况:

成功:线程获得锁;

不成功:表示Mark Word已经被其他线程修改了,存在资源竞争,此时会尝试自旋(不断尝试获取锁)来获得锁,一般会自旋是有次数限制的,比如循环10次还没有得到锁的话,就进入阻塞状态。jdk采用了自适应自旋(就是如果这次成功了,下次自旋次数会增加,如果这次失败了,下次自旋次数会减少)。如果自旋一直拿不到锁,就会升级为重量级锁

重量级锁

依赖于操作系统的互斥量(mutex)实现,操作系统中线程状态的切换比较耗费时间,但是被阻塞的线程不会CPU。

重量级锁是根据以下来实现的:

锁的升级流程

回复
  1. 不射箭 Chrome 8 in Mac OS X

    奥利给!

    Reply
  2. b Chrome 8 in Mac OS X

    <a href='www.baidu.com'>q</a>

    Reply