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


  1. 可中断
  2. 可以设置超长时间
  3. 可以设置为公平锁
  4. 可以支持多个条件变量
    与synchronized一样,都支持可重入.
    JUC并发编程八 并发架构--ReentrantLock_条件变量

验证可重入

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;

@Slf4j(topic = "c.TestReentrantLock")
public class TestReentrantLock {
private static ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) {
lock.lock();

try{
log.debug("进入主方法");
m1();
}finally {
lock.unlock();
}
}

// 测试可重入
public static void m1() {
lock.lock();
try{
log.debug("进入m1方法");
m2();
}finally {
lock.unlock();
}
}

public static void m2() {
lock.lock();
try{
log.debug("进入m2方法");
}finally {
lock.unlock();
}
}
}

验证可打断性

lock()方法不具备打断性

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;

@Slf4j(topic = "c.TestReentrantLock")
public class TestReentrantLock {
private static ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) {

// 防止无限制的等待下去

Thread t1 = new Thread(()->{
lock.lock();//lock()方法不能被打断
try{
log.debug("获取锁");
}finally {
lock.unlock();
log.debug("finally...");
}
});


lock.lock();
t1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 去打断t1,不起作用。因为lock()方法不能被打断
t1.interrupt();
}

}

locklockInterruptibly方法可以被打断,停止线程无限制的等待.

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;

@Slf4j(topic = "c.TestReentrantLock")
public class TestReentrantLock {
private static ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) {

// 防止无限制的等待下去

Thread t1 = new Thread(()->{

try{
log.debug("尝试获取锁");
lock.lockInterruptibly();//locklockInterruptibly方法可以被打断
}catch (InterruptedException e){
e.printStackTrace();
log.debug("没有或得锁, 返回");
return;
}

try{
log.debug("获取锁");
}finally {
lock.unlock(); // 释放锁
log.debug("finally...");
}
});


lock.lock();
t1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("打断t1");
// 去打断t1,不起作用。因为lock()方法不能被打断
t1.interrupt();
}
}

验证锁超时

import lombok.extern.slf4j.Slf4j;

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

@Slf4j(topic = "c.TestReentrantLock")
public class TestReentrantLock {
private static ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) {
Thread t = new Thread(()->{

// if(!lock.tryLock()){
// log.debug("获取锁失败");
// return;
// }

try {
// 尝试获取锁,如果1秒内,获取不到锁就会获取锁失败
if(!lock.tryLock(1,TimeUnit.SECONDS)){
log.debug("获取锁失败");
return;
}
} catch (InterruptedException e) {
// 表示可以调用 interrupt()方法,打断线程
log.debug("获取锁失败");
e.printStackTrace();
return;
}

try{
log.debug("获取锁成功");
}finally {
lock.unlock();
}

},"t1");


lock.lock();
log.debug("获取锁");
t.start();
try {
Thread.sleep(2000); // 睡眠2秒
} catch (InterruptedException e) {
e.printStackTrace();
}

log.debug("释放锁");
lock.unlock();

}
}

验证条件变量

import lombok.extern.slf4j.Slf4j;

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

@Slf4j(topic = "c.TestCondition")
public class TestCondition {

static boolean hasCigarette = false;
static boolean hasTakeout = false;
static ReentrantLock ROOM = new ReentrantLock();
static Condition waitCigaretteSet = ROOM.newCondition();
static Condition waitTakeoutSet = ROOM.newCondition();

public static void main(String[] args) {
new Thread(()->{
ROOM.lock();
try{
log.debug("烟送到没?[{}]",hasCigarette);
while(!hasCigarette){
log.debug("没烟,先歇会...");
try {
waitCigaretteSet.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

log.debug("开始干活...");
}finally {
ROOM.unlock();
}
},"小南").start();

new Thread(()->{
ROOM.lock();
try{
log.debug("外卖送到没?[{}]",hasTakeout);
while(!hasTakeout){
log.debug("没外卖,先歇会...");
try {
waitTakeoutSet.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

log.debug("开始干活...");
}finally {
ROOM.unlock();
}
},"小女").start();

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

new Thread(()->{
ROOM.lock();
try{
hasCigarette = true;
waitCigaretteSet.signal();
}finally {
ROOM.unlock();
}
}).start();

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

new Thread(()->{
ROOM.lock();
try{
hasTakeout = true;
waitTakeoutSet.signal();
}finally {
ROOM.unlock();
}
}).start();
}
}