1.Synchronized锁

底层是monitor监视器,每一个对象再创立的时候都会常见一个monitor监视器,在应用synchronized代码块的时候,会在代码块的前后产生一个monitorEnter和monitorexit指令,来标识这是一个同步代码块。

1.1 执行流程

线程遇到同步代码块,给这个对象monitor对象加1,当线程退出以后代码块当前,给这个对象的monitor对象减一,如果monitor指令的值为0则以后线程开释锁。

1.2 反编译源码

同步代码块反编译

public void test01(){        synchronized (this){            int num = 1 ;        }    }

两次monitorexit的作用是防止同步代码块无奈跳出,因而存在两种,失常退出和异样退出

同步办法反编译

public synchronized  void test01(){            int num = 1 ;    }

能够发现其没有在同步办法前后增加monitor指令,然而在其底层实际上也是通过monitor指令实现的,只不过相较于同步代码块来说,他是隐式的。

1.3 锁降级

JDK1.5的时候对于synchronzied做了一系列优化操作,减少了诸如:偏差锁,轻量级锁,自旋锁,锁粗化,重量级锁的概念。

1.3.1 偏差锁

在一个线程在执行获取锁的时候,以后线程会在monitor对象中存储指向该线程的ID。当线程再次进入的时候,不须要通过CAS的办法再来进行加锁或者解锁,而是检测偏差锁的ID是不是以后要进行的线程,如果是,间接进入。

偏差锁,实用于一个线程执行工作的状况

JDK1.6中,默认是开启的。能够通过-XX:-UseBiasedLocking=false参数敞开偏差锁

1.3.2 轻量级锁

轻量级锁是指锁为偏差锁的时候,该锁被其余线程尝试获取,此时偏差锁降级为轻量级锁,其余线程会通过自旋的形式尝试获取锁,线程不会阻塞,从而提供性能

降级为轻量级锁的状况有两种:

  • 敞开偏差锁
  • 有多个线程竞争偏差锁的时候

具体实现:

线程进行代码块当前,如果同步对象锁状态为无锁的状态,虚拟机将首先在以后线程的栈帧中创立一个锁记录的空间。这个空间内存储了以后获取锁的对象。

应用状况:

两个线程的相互拜访

1.3.3 重量级锁

在有超过2个线程拜访同一把锁的时候,锁主动降级为重量级锁,也就是传统的synchronized,此时其余未获取锁的线程会陷入期待状态,不可被中断。

因为依赖于monitor指令,所以其耗费系统资源比拟大

下面的三个阶段就是锁降级的过程

1.3.4 锁粗化

当在一个循环中,咱们屡次应用对同一个代码进行加锁,这个时候,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底层原理分析的文章

2. Lock锁

一个类级别的锁,须要手动开释锁。能够选择性的抉择设置为偏心锁或者不偏心锁。期待线程能够被打断。

底层是基于AQS+AOSAQS类实现具体的加锁逻辑,AOS保留获取锁的线程信息

2.1 ReentrantLock

咱们以ReentrantLock为例解析一下其加锁的过程。

2.1.1 lock办法

首先通过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();    }

2.1.2 unlock办法

代码解读:

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);    }
2.1.3 Node节点
/** 共享锁,读锁应用 */        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;

3. Lock锁和Synchronized的区别

  • Lock锁是API层面,synchronizedCPU源语级别的
  • Lock锁期待线程能够被中断,synchronized期待线程不能够被中断
  • Lock锁能够指定偏心锁和非偏心锁,synchronized只能为非偏心锁
  • Lock锁须要被动开释锁,synchronized执行完代码块当前主动开释锁
更多原创文章请关注公众号@MakerStack