在Java并发编程中,锁是控制线程访问共享资源的关键机制之一。Java提供了多种类型的锁,包括普通锁、可重入锁和公平锁。下面我将详细介绍这些锁的特点和使用方法。
普通锁(Synchronized Lock)
定义:
Java中的synchronized
关键字是最基础的锁机制,它可以用来同步方法或同步代码块。
特点:
- 互斥:同一时间只有一个线程可以进入
synchronized
代码块或方法。 - 可重入:一个线程可以多次进入自己已经持有的锁。
- 隐式获取与释放:线程在进入
synchronized
代码块时自动获取锁,在退出时自动释放锁。
示例:
public class SynchronizedExample {
private int counter = 0;
public synchronized void increment() {
counter++;
}
public static void main(String[] args) {
SynchronizedExample example = new SynchronizedExample();
Thread threadA = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread threadB = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
threadA.start();
threadB.start();
try {
threadA.join();
threadB.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Counter: " + example.counter);
}
}
在这个示例中,increment
方法使用synchronized
关键字修饰,确保同一时间只有一个线程可以修改counter
变量。
可重入锁(Reentrant Lock)
定义:
ReentrantLock
是java.util.concurrent.locks
包中的一个类,它提供了比synchronized
更灵活的锁机制。
特点:
- 显式获取与释放:线程需要显式地获取和释放锁。
- 可配置公平性:可以设置为公平锁或非公平锁。
- 支持中断:等待锁的线程可以响应中断。
示例:
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
private int counter = 0;
public void increment() {
lock.lock();
try {
counter++;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockExample example = new ReentrantLockExample();
Thread threadA = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread threadB = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
threadA.start();
threadB.start();
try {
threadA.join();
threadB.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Counter: " + example.counter);
}
}
在这个示例中,我们使用ReentrantLock
来控制对counter
变量的访问。lock
和unlock
方法显式地控制锁的获取和释放。
公平锁(Fair Lock)
定义:
公平锁是一种锁机制,它试图按照线程请求锁的顺序来分配锁,以确保每个线程都能得到公平的访问机会。
特点:
- 公平性:按照请求顺序分配锁,避免某些线程长时间等待。
- 性能:公平锁通常比非公平锁慢,因为它需要维护一个等待队列。
示例:
import java.util.concurrent.locks.ReentrantLock;
public class FairLockExample {
private final ReentrantLock lock = new ReentrantLock(true); // 创建公平锁
private int counter = 0;
public void increment() {
lock.lock();
try {
counter++;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
FairLockExample example = new FairLockExample();
Thread threadA = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread threadB = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
threadA.start();
threadB.start();
try {
threadA.join();
threadB.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Counter: " + example.counter);
}
}
在这个示例中,我们创建了一个公平锁ReentrantLock
,并通过lock
和unlock
方法来控制对共享资源的访问。
总结
- 普通锁(
synchronized
)是最基础的锁机制,它隐式地获取和释放锁。 - 可重入锁(
ReentrantLock
)提供了更灵活的锁机制,包括显式获取与释放锁、可配置公平性以及支持中断。 - 公平锁是一种锁机制,它试图按照线程请求锁的顺序来分配锁,以确保每个线程都能得到公平的访问机会。
通过理解和使用这些锁的概念,你可以更有效地控制并发程序中的线程访问共享资源的方式,从而提高程序的稳定性和性能。在实际开发中,还应考虑使用Java并发库提供的高级工具和技术来简化并发编程的复杂性。