可重入锁
如果一个线程外层函数获取锁之后,内层函数也会获取锁。同一线程在外层方法获取锁的时候,再进入内层方法会自动获取锁。也就是说,线程可以进入任何一个它已经拥有的锁所同步着的代码块。ReentrantLock 和 synchronized 就是典型的可重入锁。
(1). 基于 synchronized
public class ReentrantLockTest {
public static void main(String[] args) {
Phone phone = new Phone();
// 第一个线程
new Thread(() -> {
phone.sendMsg();
}, "t1").start();
// 第二个线程
new Thread(() -> {
phone.sendMsg();
}, "t2").start();
}
}
class Phone {
// 发送短信同步方法
public synchronized void sendMsg() {
System.out.println(Thread.currentThread().getName() + " called sendMsg()");
// 进入另外一个同步着的方法
sendEmail();
}
// 发送邮件同步方法
public synchronized void sendEmail() {
System.out.println(Thread.currentThread().getName() + " ******called sendEmail()");
}
}
运行结果:
t1 called sendMsg() // t1线程在外层方法获取锁的时候
t1 ******called sendEmail() // t1再进入内层方法会自动获取锁
t2 called sendMsg()
t2 ******called sendEmail()
(2). 基于 ReentrantLock
public class ReentrantLockTest {
public static void main(String[] args) {
Phone phone = new Phone();
// 第一个线程
Thread t1 = new Thread(phone, "t1");
// 第二个线程
Thread t2 = new Thread(phone, "t2");
t1.start();
t2.start();
}
}
class Phone implements Runnable {
ReentrantLock lock = new ReentrantLock();
// 发送短信方法
public void sendMsg() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " called sendMsg()");
// 进入另一个方法
sendEmail();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
// 发送邮件方法
public void sendEmail() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " ******called sendEmail()");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
@Override
public void run() {
sendMsg();
}
}
运行结果:
t1 called sendMsg() // t1线程在外层方法获取锁的时候
t1 ******called sendEmail() // t1再进入内层方法会自动获取锁
t2 called sendMsg()
t2 ******called sendEmail()