Reentrant Lock

相比synchronized,它具备以下特点:

  • 可中断
  • 可以设置超时时间
  • 可以设置为公平锁
  • 支持多个条件变量:进入不同的waitSet

与synchronized一样,支持可重入

基本语法

reentrantLock.lock()
try{
	//临界区
}finally {
	//释放锁
	reentrantLock.unlock();
}

可重入

可重入是指同一个线程如果首次获得了这把锁,因为它是这把锁的拥有者,因此有权利再次获取这把锁。

如果是不可重入,那么第二次获得锁时,自己也会被锁挡住。

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;

@Slf4j(topic = "reentrantLockTest")
public class ReentrantLockTest {
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        lock.lock();
        try {
            System.out.println("进入main");
            m1();
        }finally {
            lock.unlock();
        }
    }

    public static void m1() {
        lock.lock();
        try {
            System.out.println("进入m1");
            m2();
        }finally {
            lock.unlock();
        }
    }

    public static void m2() {
        lock.lock();
        try {
            System.out.println("进入m2");
        }finally {
            lock.unlock();
        }
    }
}

image

结果说明reentrantLock可重入

可打断

使用reentrantLock.lockInterruptibly();,尝试获取一个可以被打断的锁
使用reentrantLock.lock();,尝试获取一个不可被打断的锁

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;

@Slf4j(topic = "testInterruptibly")
public class ReentrantLockTestInterruptibly {
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            try {
                log.debug("尝试获取一个可打断的锁");
                lock.lockInterruptibly();
            } catch (InterruptedException e) {
                e.printStackTrace();
                log.debug("没有获得到锁,直接返回");
                return;
            }

            log.debug("获取到锁");
            lock.unlock();

        },"t1");


        //主线程加锁
        lock.lock();
        t1.start();
        
        Thread.sleep(2000);

        t1.interrupt();
    }
}

image

改为lock.lock();,则t1.interrupt();不能打断。

锁超时

立即失败

lock.tryLock()尝试获得锁。如果成功,则返回true获得锁,如果失败,则返回false,不等待。

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class ReentrantLockTestTimeout {
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread( () -> {
            log.debug("尝试获得锁..");
            if ( !lock.tryLock()){
                log.debug("未获得锁.");
                return;
            }
            try {
                log.debug("获得到锁,执行临界区代码");
            } finally {
                lock.unlock();
            }
        },"t1");

        lock.lock();
        t1.start();
    }
}

image

超时失败

import lombok.extern.slf4j.Slf4j;

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

@Slf4j
public class ReentrantLockTestTimeout {
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread( () -> {
            log.debug("尝试获得锁..");
            try {
                if ( !lock.tryLock(2, TimeUnit.SECONDS)){
                    log.debug("超时未获得锁.");
                    return;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                log.debug("被打断,未获得锁");
                return;
            }
            try {
                log.debug("获得到锁,执行临界区代码");
            } finally {
                lock.unlock();
            }
        },"t1");

        lock.lock();
        t1.start();
        Thread.sleep(3000);
//        t1.interrupt();
        lock.unlock();

    }
}

image

公平锁

ReentrantLock默认是不公平锁
ReentrantLock lock = new ReentrantLock(true);改为公平锁。
公平锁一般没必要设置,会降低并发度。公平锁主要用于解决饥饿问题。

条件变量

synchronized中也有条件变量。当条件不满足时进入waitSet等待。

ReentrantLock的条件变量比synchronized的强大之处在于,ReentrantLock支持多个条件变量,有多个等待队列。

使用流程:

  1. await前需要获得锁
  2. await执行后会释放锁,进入conditionObject等待
  3. await的线程被唤醒(打断/超时),重新竞争lock锁
  4. 竞争lock锁成功后,从await后继续执行
import lombok.extern.slf4j.Slf4j;

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

@Slf4j(topic = "testCondition")
public class ReentrantLockTestCondition {
    static ReentrantLock ROOM = new ReentrantLock();

    static Condition waitSet1 = ROOM.newCondition();
    static Condition waitSet2 = ROOM.newCondition();

    static boolean flag1 = false;
    static boolean flag2 = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            ROOM.lock();
            try {
                while (!flag1){
                    try {
                        log.debug("条件不满足,继续等待..");
                        waitSet1.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("条件满足,执行临界区代码");
            } finally {
                ROOM.unlock();
            }
        },"t1").start();


        new Thread(()->{
            ROOM.lock();
            try {
                while (!flag2){
                    try {
                        log.debug("条件不满足,继续等待..");
                        waitSet2.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("条件满足,执行临界区代码");
            } finally {
                ROOM.unlock();
            }
        },"t2").start();

        Thread.sleep(2000);

        new Thread(()->{
            ROOM.lock();
            try {
                log.debug("flag1置为true");
                flag1 = true;
                waitSet1.signal();
            } finally {
                ROOM.unlock();
            }
        },"c1").start();


        new Thread(()->{
            ROOM.lock();
            try {
                log.debug("flag2置为true");
                flag2 = true;
                waitSet2.signal();
            } finally {
                ROOM.unlock();
            }
        },"c2").start();
    }

}

image

posted @ 2024-01-23 14:26  ︶ㄣ演戲ㄣ  阅读(12)  评论(0)    收藏  举报