ReentrantLock

一、概述

  同步代码块/同步方法具有的功能Lock都具有,另外ReetranttLock具有其他功能。例如公平锁、响应中断、获取锁时限时等待、结合Condition实现等待机制。

  ReetranttLock是可重入锁的独占锁。比起synchronized功能更加丰富,实现公平锁实现、支持中断响应以及实现获取锁限时等待等等。可以配合一个或多个Condition条件方便等待通知机制。(面试的时候回答这个,可以再扯一扯synchronized的优化机制、公平锁非公平锁、死锁的产生以及解决等相关知识)

二、实现公平锁

https://blog.csdn.net/cgj296645438/article/details/79442675

  公平锁:先来先服务,可以防止饥饿情况出现。非公平所则随机分配锁的使用权,性能更好但是会有饥饿情况。

//公平
ReentrantLock lock = new ReentrantLock(true);
//非公平
ReentrantLock lock = new ReentrantLock();
ReentrantLock lock = new ReentrantLock(false);

 二、响应中断

  synchronized实现锁时,阻塞在锁上的线程除非获取锁否则将一直等待下去,也就是说这种无限等待获取锁的行为无法被中断。ReetranttLock给我们提供了一个可以响应中断的获取锁的方法lockInterruptibly(),可以用来解决死锁问题。

package com.reentrantLock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Millet
 * @date 2020/3/31 12:00
 */
public class Main {
    private static ReentrantLock lock1 = new ReentrantLock();
    private static ReentrantLock lock2 = new ReentrantLock();
    public static void main(String[] args) {

         final Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock1.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName()+"获得了锁1");
                    Thread.sleep(500);
                    lock2.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName()+"获得了锁2");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock1.unlock();
                    lock2.unlock();
                }
            }
        },"t1"){};
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock2.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName()+"获得了锁2");
                    Thread.sleep(500);
                    lock1.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName()+"获得了锁1");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock1.unlock();
                    lock2.unlock();
                }
            }
        },"t2"){};
        t1.start();
        t2.start();
new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } t1.interrupt(); } }).start(); } }

  出现死锁时,直接中断,抛出异常中断死锁。

三、获取锁时限时等待

  提供了获取锁时限时等待的方法tryLock(),可以用来解决死锁问题。

/**
*timeout:等待获取锁的时间
*unit:时间单位
不写参数则立即返回是否获取锁
*/ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); }
package com.reentrantLock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Millet
 * @date 2020/3/31 14:18
 */

public class Main2 {
    private static ReentrantLock lock1 = new ReentrantLock();
    private static ReentrantLock lock2 = new ReentrantLock();
    public static void main(String[] args) {

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    if(lock1.tryLock(5, TimeUnit.SECONDS)){
                        System.out.println(Thread.currentThread().getName()+"获得了锁1");
                        Thread.sleep(500);
                        if(lock2.tryLock(5, TimeUnit.SECONDS))
                            System.out.println(Thread.currentThread().getName()+"获得了锁2");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    if (lock1.isLocked())
                        lock1.unlock();
                    if (lock2.isLocked())
                        lock2.unlock();
                }
            }
        },"t1"){};
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    if(lock2.tryLock(5, TimeUnit.SECONDS)){
                        System.out.println(Thread.currentThread().getName()+"获得了锁2");
                        Thread.sleep(500);
                        if(lock1.tryLock(5, TimeUnit.SECONDS))
                            System.out.println(Thread.currentThread().getName()+"获得了锁1");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    if (lock1.isLocked())
                        lock1.unlock();
                    if (lock2.isLocked())
                        lock2.unlock();
                }
            }
        },"t2"){};
        t1.start();
        t2.start();
    }
}

四、结合Condition实现等待通知机制

  使用synchronized结合Object的wait和notify可以实现线程间的等待通知机制。ReentrantLock结合Condition同样可以实现这个功能。

  详情点击

原文地址:https://www.cnblogs.com/qmillet/p/12605329.html