语法:
// 获取锁
reentrantLock.lock();
try {
// 临界区
} finally {
// 释放锁
reentrantLock.unlock();
}
连续三次上锁。
@Slf4j(topic = "c.test")
public class Reentrant {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
lock.lock();
try {
m1();
log.debug("上锁");
} finally {
lock.unlock();
}
}
public static void m1(){
lock.lock();
try {
log.debug("上锁");
m2();
} finally {
lock.unlock();
}
}
public static void m2(){
lock.lock();
try {
log.debug("上锁");
} finally {
lock.unlock();
}
}
}
可以发现,上锁都成功了。
使用lockInterruptibly方法,如果无竞争那么就会获得lock锁;有有竞争会进入阻塞队列,可以被其他线程用interrupt方法打断。
@Slf4j(topic = "c.test")
public class Reentrant {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("启动");
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
log.debug("我被打断了");
return;
}
try {
log.debug("获得了锁");
} finally {
//释放锁
lock.unlock();
}
}, "t1");
lock.lock();
t1.start();
try {
Thread.sleep(1000);
t1.interrupt();
}
finally {
lock.unlock();
}
}
}
如果用lock方法那么是无法被打断的,会一直等待。
使用trylock方法,尝试获得锁,如果能获得锁就获得,返回true,否则返回false。
立即失败:
@Slf4j(topic = "c.test")
public class Reentrant {
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();
try {
Thread.sleep(1000);
}
finally {
lock.unlock();
}
}
}
超时失败:
lock.tryLock(1, TimeUnit.SECONDS),第一个参数是数字,第二个参数是单位。
@Slf4j(topic = "c.test")
public class Reentrant {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
log.debug("启动");
try {
if(!lock.tryLock(1, TimeUnit.SECONDS)){
log.debug("没获得锁!");
return;
}
}catch (InterruptedException e){
e.printStackTrace();
}
try {
log.debug("获得了锁");
} finally {
//释放锁
lock.unlock();
}
}, "t1");
lock.lock();
t1.start();
try {
Thread.sleep(1000);
}
finally {
lock.unlock();
}
}
}
锁超时可以用来优化哲学家问题:让Chopstick继承ReentrantLock,然后使用tryLock优化。
可以加一个boolean参数,true代表公平锁,默认是不公平的。
ReentrantLock lock = new ReentrantLock(true);
但是一般不用,公平锁会降低并发度。
ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的。
wait和notify的模板语法中,每次都要notifyAll,然后所有的wait线程都被唤醒,如果条件没满足,就是虚假唤醒。
但是使用了多个条件变量,我们就不需要盲目地唤醒所有线程了。
使用newCondition()创建一个条件变量,这个案例中模拟两个线程,一个线程需要吃苹果才能工作,一个线程需要卫生纸才能工作。
private static ReentrantLock lock = new ReentrantLock();
static Condition hasApple = lock.newCondition();
static Condition hasTissue = lock.newCondition();
static boolean apple = false;
static boolean tissue = false;
线程1:hasApple.await();方法,可以让当前线程进入等待。
new Thread(()->{
try {
lock.lock();
while(!apple){
try {
hasApple.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("苹果来了,开始干活");
}
finally {
lock.unlock();
}
}, "APPLE").start();
还需要一个唤醒线程,这里就可以看出来条件变量的优势,只需要唤醒hasApple中的线程即可,不会导致hasTissue中的线程被虚假唤醒。
private static void sendApple(){
lock.lock();
try {
log.debug("送苹果来了");
apple = true;
hasApple.signal();
}
finally {
lock.unlock();
}
}
完整代码:
@Slf4j(topic = "c.test")
public class Reentrant {
private static ReentrantLock lock = new ReentrantLock();
static Condition hasApple = lock.newCondition();
static Condition hasTissue = lock.newCondition();
static boolean apple = false;
static boolean tissue = false;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
try {
lock.lock();
while(!apple){
try {
hasApple.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("苹果来了,开始干活");
}
finally {
lock.unlock();
}
}, "APPLE").start();
new Thread(()->{
try {
lock.lock();
while(!tissue){
try {
hasTissue.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("卫生纸来了,开始干活");
}
finally {
lock.unlock();
}
}, "TISSUE").start();
Thread.sleep(1000);
sendApple();
Thread.sleep(2000);
sendTissue();
}
private static void sendApple(){
lock.lock();
try {
log.debug("送苹果来了");
apple = true;
hasApple.signal();
}
finally {
lock.unlock();
}
}
private static void sendTissue(){
lock.lock();
try {
log.debug("送卫生纸来了");
tissue = true;
hasTissue.signal();
}
finally {
lock.unlock();
}
}
}
输出: