底层是monitor
监视器,每个对象再建立的时候都会常见一个monitor
监视器,在使用synchronized
代码块的时候,会在代码块的先后产生一个monitorEnter和monitorexit
指令,来标识这是一个同步代码块。java
线程遇到同步代码块,给这个对象monitor
对象加1
,当线程退出当前代码块之后,给这个对象的monitor
对象减一,若是monitor
指令的值为0
则当前线程释放锁。node
同步代码块反编译安全
public void test01(){ synchronized (this){ int num = 1 ; } }
两次monitorexit
的做用是避免同步代码块没法跳出,所以存在两种,正常退出和异常退出性能
同步方法反编译优化
public synchronized void test01(){ int num = 1 ; }
能够发现其没有在同步方法先后添加monitor
指令,可是在其底层实际上也是经过monitor
指令实现的,只不过相较于同步代码块来讲,他是隐式的。ui
在JDK1.5
的时候对于synchronzied
作了一系列优化操做,增长了诸如:偏向锁,轻量级锁,自旋锁,锁粗化,重量级锁的概念。this
在一个线程在执行获取锁的时候,当前线程会在monitor
对象中存储指向该线程的ID。当线程再次进入的时候,不须要经过CAS的方法再来进行加锁或者解锁,而是检测偏向锁的ID是否是当前要进行的线程,若是是,直接进入。spa
偏向锁,适用于一个线程执行任务的状况线程
在JDK1.6
中,默认是开启的。能够经过-XX:-UseBiasedLocking=false
参数关闭偏向锁code
轻量级锁是指锁为偏向锁的时候,该锁被其余线程尝试获取,此时偏向锁升级为轻量级锁,其余线程会经过自旋的方式尝试获取锁,线程不会阻塞,从而提供性能
升级为轻量级锁的状况有两种:
具体实现:
线程进行代码块之后,若是同步对象锁状态为无锁的状态,虚拟机将首先在当前线程的栈帧中建立一个锁记录的空间。这个空间内存储了当前获取锁的对象。
使用状况:
两个线程的互相访问
在有超过2个线程访问同一把锁的时候,锁自动升级为重量级锁,也就是传统的synchronized
,此时其余未获取锁的线程会陷入等待状态,不可被中断。
因为依赖于monitor
指令,因此其消耗系统资源比较大
上面的三个阶段就是锁升级的过程
当在一个循环中,咱们屡次使用对同一个代码进行加锁,这个时候,JVM会自动实现锁粗化,即在循环外进行添加同步代码块。
代码案例:
锁粗化以前:
for (int i = 0; i < 10; i++) { synchronized (LockBigDemo.class){ System.out.println(); } }
锁粗化以后:
synchronized (LockBigDemo.class){ for (int i = 0; i < 10; i++) { System.out.println(); } }
本次关于synchronized
的底层原理没有以代码的方式展开,以后笔者会出一篇synchronized
底层原理剖析的文章
一个类级别的锁,须要手动释放锁。能够选择性的选择设置为公平锁或者不公平锁。等待线程能够被打断。
底层是基于AQS
+AOS
。AQS
类完成具体的加锁逻辑,AOS
保存获取锁的线程信息
咱们以ReentrantLock
为例解析一下其加锁的过程。
首先经过ReentrantLock
的构造方法的布尔值判断建立的锁是公平锁仍是非公平锁。
假设如今建立的是非公平锁,他首先会判断锁有没有被获取,若是没有被获取,则直接获取锁;
若是锁已经被获取,执行一次自旋,尝试获取锁。
若是锁已经被获取,则将当前线程封装为AQS
队列的一个节点,而后判断当前节点的前驱节点是否是HEAD
节点,若是是,尝试获取锁;若是不是。则寻找一个安全点(线程状态位SIGNAL=-1
的节点)。
开始不断自旋。判断前节点是否是HEAD
节点,若是是获取锁,若是不是挂起。
源码解读:
lock
final void lock() { //判断是否存在锁 if (compareAndSetState(0, 1)) //获取锁 setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
//非公平锁的自旋逻辑 protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); //获取锁状态 int c = getState(); //若是锁没被获取,获取锁 if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } //当前线程已经获取到了锁 else if (current == getExclusiveOwnerThread()) { //线程进入次数增长 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
//将线程封装为一个线程节点,传入锁模式,排他或者共享 private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); // 获取尾节点 Node pred = tail; //若是尾节点不为Null,直接将这个线程节点添加到队尾 if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } //为空,自旋设置尾节点 enq(node); return node; } private Node enq(final Node node) { for (;;) { Node t = tail; //初始化 if (t == null) { // Must initialize if (compareAndSetHead(new Node())) tail = head; } else { node.prev = t; //将头结点和尾结点都设置为当前节点 if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }
//尝试入队 final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { //获取节点的前驱节点,若是前驱节点为head节点,则尝试获取锁 final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } //若是不是,寻找安全位 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { int ws = pred.waitStatus; //前驱节点已经安全 if (ws == Node.SIGNAL) return true; //前驱节点不安全,寻找一个线程状态为`Signal`的节点做为前驱节点 if (ws > 0) { do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { //不然直接设置这个前驱节点的线程等待状态值 compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } return false; } //中断线程 private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }
代码解读:
public void unlock() { sync.release(1); }
public final boolean release(int arg) { //尝试释放锁 if (tryRelease(arg)) { //获取队列头元素,唤醒该线程节点,执行任务 Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
protected final boolean tryRelease(int releases) { int c = getState() - releases; //判断是否为当前线程拥有锁 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; //释放成功 if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
private void unparkSuccessor(Node node) { int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); Node s = node.next; if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } //唤醒下一个节点 if (s != null) LockSupport.unpark(s.thread); }
/** 共享锁,读锁使用 */ static final Node SHARED = new Node(); /** 独占锁*/ static final Node EXCLUSIVE = null; /** 不安全线程 */ static final int CANCELLED = 1; /** 须要进行线程唤醒的线程 */ static final int SIGNAL = -1; /**condition等待中 */ static final int CONDITION = -2; //线程等待状态 volatile int waitStatus; volatile Node prev; volatile Node next; volatile Thread thread; Node nextWaiter;
Lock
锁是API层面,synchronized
是CPU
源语级别的Lock
锁等待线程能够被中断,synchronized
等待线程不能够被中断Lock
锁能够指定公平锁和非公平锁,synchronized
只能为非公平锁Lock
锁须要主动释放锁,synchronized
执行完代码块之后自动释放锁更多原创文章请关注公众号@MakerStack