相比synchronized,ReentrantLock具备以下特点:
- 可中断
- 可以设置超长时间
- 可以设置为公平锁
- 可以支持多个条件变量
与synchronized一样,都支持可重入.
验证可重入
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();
}
}