简述 Java 中的线程同步机制,synchronized 关键字和 ReentrantLock 的区别是什么?
- 语法层面
synchronized:是 Java 中的关键字,是一种内置的同步机制。它可以修饰方法或者代码块,使用起来比较简洁。例如:
// 同步方法
public synchronized void method() {
// 同步代码
}
// 同步代码块
public void anotherMethod() {
synchronized (this) {
// 同步代码
}
}
ReentrantLock:是一个类,需要显式地创建锁对象,并调用 lock() 和 unlock() 方法来进行加锁和解锁操作。例如:
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
private final ReentrantLock lock = new ReentrantLock();
public void method() {
lock.lock();
try {
// 同步代码
} finally {
lock.unlock();
}
}
}
- 锁的获取和释放
synchronized:由 JVM 自动获取和释放锁。当线程进入同步方法或同步代码块时,JVM 会自动获取锁;当线程退出同步方法或同步代码块时,JVM 会自动释放锁。
ReentrantLock:需要手动获取和释放锁。如果忘记调用 unlock() 方法,会导致锁无法释放,从而产生死锁问题。因此,通常将 unlock() 方法放在 finally 块中,以确保锁一定会被释放。 - 锁的特性
可重入性:两者都具有可重入性,即同一个线程可以多次获取同一把锁而不会发生死锁。
公平性:
synchronized:是非公平锁,即线程获取锁的顺序是不确定的,可能会导致某些线程长时间得不到锁。
ReentrantLock:可以通过构造函数指定是公平锁还是非公平锁。公平锁会按照线程请求锁的顺序依次分配锁,保证每个线程都有机会获取锁。例如:
import java.util.concurrent.locks.ReentrantLock;
public class FairLockExample {
private final ReentrantLock fairLock = new ReentrantLock(true);
public void method() {
fairLock.lock();
try {
// 同步代码
} finally {
fairLock.unlock();
}
}
}
- 锁的中断
synchronized:线程在等待获取锁的过程中不能被中断,只能一直等待。
ReentrantLock:提供了可中断的锁获取方式,即线程在等待获取锁的过程中可以被中断。例如:
import java.util.concurrent.locks.ReentrantLock;
public class InterruptibleLockExample {
private final ReentrantLock lock = new ReentrantLock();
public void method() throws InterruptedException {
lock.lockInterruptibly();
try {
// 同步代码
} finally {
lock.unlock();
}
}
}
- 锁的尝试获取
synchronized:没有提供尝试获取锁的功能,线程只能一直等待锁的释放。
ReentrantLock:提供了 tryLock() 方法,用于尝试获取锁。如果锁可用,则获取锁并返回 true;如果锁不可用,则立即返回 false,而不会阻塞线程。例如:
import java.util.concurrent.locks.ReentrantLock;
public class TryLockExample {
private final ReentrantLock lock = new ReentrantLock();
public void method() {
if (lock.tryLock()) {
try {
// 同步代码
} finally {
lock.unlock();
}
} else {
// 锁不可用,执行其他操作
}
}
}

浙公网安备 33010602011771号