1、可重入锁(递归锁)
    是指在同一线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提,锁对象得是同一对象),不会因为之前已经获取过没有释放而阻塞。
    java中的ReentrantLock和synchronized都是可重入锁,可重入锁的有点就是可以避免死锁。
    可重入锁种类
    隐式锁(即synchronized关键字使用的锁)默认是可重入锁。
    monitorenter monitorexit monitorexit出现两次是为了保证出现异常时彻底释放锁
    可重入锁的实现机制
    每个锁对象拥有一个锁计数器和一个指向持有该锁的线程的指针。
    当执行monitorenter时,如果目标锁对象的计数器为零,那么说明它没有被其他线程所持有,java虚拟机会将该锁对象的持有线程设置为当前线程,并将计数器+1。
    在目标锁对象的计数器不为零的情况下,如果锁对象的持有线程是当前线程,那么java线程将计数器+1,否则需要等待,知道持有线程释放锁。
    当执行monitorexit时,java虚拟机则需要将锁对象的计数器减1.计数器为零代表锁已经被释放。
    显示锁(即Lock)也有ReentrantLock这样的可重入锁。
    2、LockSupport(用于创建锁和其他同步类的基本线程阻塞原语)
    线程等待唤醒机制(wait/notify)加强版
    三种线程等待唤醒的方法
    方式一:使用object类中的wait()方法让线程等待,使用object类中的notify()方法唤醒线程

    1. public class LockSupportDemo {
    2. static Object objectLock = new Object();
    3. public static void main(String[] args) {
    4. new Thread(() -> {
    5. synchronized (objectLock) {
    6. System.out.println(Thread.currentThread().getName() + "\t" + "====come in");
    7. try {
    8. objectLock.wait();
    9. } catch (InterruptedException e) {
    10. e.printStackTrace();
    11. }
    12. System.out.println(Thread.currentThread().getName() + "\t" + "====被唤醒");
    13. }
    14. }, "A").start();
    15. new Thread(() -> {
    16. synchronized (objectLock) {
    17. objectLock.notify();
    18. System.out.println(Thread.currentThread().getName() + "\t" + "====通知");
    19. }
    20. }, "B").start();
    21. }
    22. }

    问题:wait和notify只能在synchronized代码块中执行,并且notify只能在wait之后若顺序颠倒会出现阻塞现象
    方式二:使用JUC包中的Condition的await()方法让线程等待,使用signal()方法唤醒线程

    1. public class LockSupportDemo {
    2. static Lock lock = new ReentrantLock();
    3. static Condition condition = lock.newCondition();
    4. public static void main(String[] args) {
    5. new Thread(() -> {
    6. lock.lock();
    7. try {
    8. System.out.println(Thread.currentThread().getName()+ "\t"+ "====come in");
    9. condition.await();
    10. System.out.println(Thread.currentThread().getName()+ "\t"+ "====被唤醒");
    11. } catch (InterruptedException e) {
    12. e.printStackTrace();
    13. } finally {
    14. lock.unlock();
    15. }
    16. },"A").start();
    17. new Thread(() -> {
    18. lock.lock();
    19. try {
    20. condition.signal();
    21. System.out.println(Thread.currentThread().getName()+ "\t"+ "====通知");
    22. } finally {
    23. lock.unlock();
    24. }
    25. },"B").start();
    26. }
    27. }

    问题:必须在锁块lock中,且需要先await再signal
    方式三:LockSupport类可以阻塞当前线程以及唤醒执行被阻塞的线程

    1. public class LockSupportDemo {
    2. public static void main(String[] args) throws InterruptedException {
    3. Thread a = new Thread(()->{
    4. System.out.println(Thread.currentThread().getName()+"\t"+"====come in");
    5. LockSupport.park();
    6. System.out.println(Thread.currentThread().getName()+"\t"+"====被唤醒");
    7. },"a");
    8. a.start();
    9. Thread.sleep(3000);
    10. Thread b = new Thread(()->{
    11. LockSupport.unpark(a);
    12. System.out.println(Thread.currentThread().getName()+"\t"+"====通知");
    13. },"b");
    14. b.start();
    15. }
    16. }

    优点,unpark()可以在park()之前执行,不需要再任何操作之后
    image.png