Lock、Synchronized锁区别解析( 四 )


乐观锁: 先保存一个参考数据 , 然后修改当前线程空间的变量 , 然后准备更新到主内存中去 , 在更新之前检查主内存对应的参考数据是否与之前保存的参考数据一致 , 如果一致更新到主内存 , 如果不一样那么此次更新作废 。
2、轻量级锁
Lock、Synchronized锁区别解析文章插图
轻量级锁适用于线程数量少且执行时间短的代码块 。 在线程还未得到CPU调度时 , 首先会在该线程的栈中开启一块区域作为lock record , 然后将对象头的 Mark Word 部分拷贝到 lock record 位置 , 然后尝试将对象对象头 Mark Word 轻量级锁部分的指向栈的指针指向自己线程的lock record , 如果成功就表明该线程得到了锁 , CPU就会调度 。 详细的执行过程是:
1.如果这个对象锁是刚刚升级到轻量级锁且锁对应对象的mark word的偏向锁部分存储的 threadId 对应的线程没有执行完当前对应的代码 , 那么系统就会先将CPU交给 threadId 对应的线程 , 让他先执行完 。 过程就是先在该线程的栈中开启一块区域作为lock record , 然后将mark word拷贝到 lock record , 再将轻量级锁部分的指针指向 lock record 。 随后开始执行锁修饰的代码块 , 执行完毕后会进行两次检查:1.对象头的Mark Word中锁记录指针是否还是指向当前线程的lock record部分 2.lock record是否还与对象头的Mark Word一致 。 如果一致 , 就释放锁资源 。 如果不一致就将锁升级为重量级锁 , 然后释放 。
2.如果是普通的线程 , 那么首先还是在当前线程的栈中开启一块区域作为lock record , 然后将对象头的 Mark Word 部分拷贝到 lock record 位置 , 然后尝试将对象对象头 Mark Word 轻量级锁部分的指向栈的指针指向自己线程的lock record ,
1.如果成功 , 就继续执行后面代码 ,
2.如果失败就以自旋锁方式继续尝试 ,
1.如果一定次数还是没有获取到锁 , 那么就将锁膨胀为重量级锁 。
2.如果成功执行锁修饰的代码 , 执行完会再进行两个检查 , 如果符合就释放锁 。 不符合就膨胀成重量级锁 , 然后再释放 。
3、重量级锁重量级锁前面也说过了 , 就是一个线程在执行时 , 其他线程就先保存当前线程状态 , 然后进入 "休眠" 状态 , 乖乖等待CPU分配 , 得到CPU后才会读取上一次保存的状态 , 然后继续执行 。 它的执行逻辑还是先判断Mark Word部分的锁标志位 , 是10就说明是重量级锁 , 然后先来的尝试获取 , 得到CPU , 继续执行 , 后面的线程就需要等待进行一次上下文切换 。
总结:正是因为 synchronized 锁升级机制的存在 , 使得 synchronized 的效率不再那么低 。
等待-通知模型在一个线程执行 synchronized 修饰的代码块时 , 其他线程并不是必须等到该线程执行完才可能得到 CPU 调度 , 对于某些业务场景 , 需要我们在一段代码中进行线程地来回切换 。 这就需要说到 "等待-通知" 模型了 , 在说这个模型前 , 要先了解 Object 的 wait() 方法
1 public final void wait() throws InterruptedException {2wait(0);3 }4 5 6 7 8 9 public final native void wait(long timeout) throws InterruptedException;可以看到 wait(long timeout) 是使用 native 修饰的 , 是一个本地方法 , 用 C、C++实现的 , 这个方法作用就是让拥有这个对象的线程释放掉这个对象 , 进入 "休眠", 并让出 CPU , 让其他线程去得到对象资源执行 。 与其对应的就是 notify() 方法 , 它也是 Object 类的方法 , 这个方法会随机让该对象对应锁的一个 "休眠" 的线程 "苏醒" , 然后参与CPU的竞争中 。 还有一个 notifyAll() 是让对象对应锁的所有 "休眠" 的线程 "苏醒" 。 下面来看一个例子
1 public class CoTest01 { 2public static void main(String[] args) { 3SynContainer container = new SynContainer(); 4new Productor(container).start(); 5new Consumer(container).start(); 6} 7 } 8 //生产者 9 class Productor extends Thread{10SynContainer container;11public Productor(SynContainer container) {12this.container = container;13}14 15public void run() {16//生产17 //synchronized (container) {18for(int i=0;i