Java 添加进程锁
引言
在多线程编程中,有时候需要确保多个线程不会同时访问特定的代码块或资源。为了避免数据竞争和不一致的状态,可以使用进程锁来进行同步。进程锁是一种并发控制机制,它确保在同一时间只有一个线程可以访问被锁定的代码块或资源。
Java 提供了多种实现进程锁的方法,比如使用 synchronized
关键字、ReentrantLock
类等。本文将介绍这些方法,并提供示例代码来说明如何使用它们。
使用 synchronized 关键字
synchronized
关键字是 Java 中最基本和简单的同步机制。它可以用于修饰方法或代码块,以确保同一时间只有一个线程可以执行被修饰的代码。
修饰方法
可以将 synchronized
关键字直接应用于方法上,将整个方法体作为临界区。下面是一个使用 synchronized
修饰方法的示例:
public class SynchronizedExample {
private int counter = 0;
public synchronized void increment() {
counter++;
}
public synchronized void decrement() {
counter--;
}
public int getCounter() {
return counter;
}
}
在上述代码中,increment
和 decrement
方法都被用 synchronized
修饰,这意味着在同一时间只有一个线程可以执行这两个方法。这样就可以确保 counter
变量的增减操作是线程安全的。
修饰代码块
除了修饰方法,synchronized
还可以修饰代码块。通过将关键字应用于代码块,可以将更精确的部分作为临界区。
下面是一个使用 synchronized
修饰代码块的示例:
public class SynchronizedExample {
private int counter = 0;
public void increment() {
synchronized (this) {
counter++;
}
}
public void decrement() {
synchronized (this) {
counter--;
}
}
public int getCounter() {
return counter;
}
}
在上述代码中,increment
和 decrement
方法中的 synchronized (this)
块表示只有一个线程可以同时进入这个块中的代码。这样同样可以确保 counter
变量的增减操作是线程安全的。
使用 ReentrantLock 类
ReentrantLock
类是 Java 提供的另一种实现进程锁的方法。与 synchronized
关键字相比,ReentrantLock
提供了更多的灵活性和功能。
下面是一个使用 ReentrantLock
的示例:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private int counter = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
counter++;
} finally {
lock.unlock();
}
}
public void decrement() {
lock.lock();
try {
counter--;
} finally {
lock.unlock();
}
}
public int getCounter() {
return counter;
}
}
在上述代码中,ReentrantLock
的实例是用 lock
方法进行加锁操作的,与之对应的是使用 unlock
方法进行解锁操作。这样可以确保同一时间只有一个线程可以进入临界区,从而实现线程安全。
进程锁的选择
在使用进程锁时,需要根据实际情况选择合适的方法。synchronized
是最简单和最常用的方法,但它的功能相对有限。而 ReentrantLock
则提供了更多的功能,比如可重入性、公平性等。
下表是 synchronized
和 ReentrantLock
的一些比较:
特性 | synchronized | ReentrantLock |
---|---|---|
可重入性 | 支持 | 支持 |
公平性 | 不支持 | 支持 |
中断响应 | 不支持 | 支持 |