本文目录导读:

我将为您提供一个完整的公平锁案例,帮助您理解公平锁的特性。
什么是公平锁?
公平锁是指多个线程按照申请锁的顺序来获取锁,先到先得,而非公平锁则允许线程"插队"。
完整案例
import java.util.concurrent.locks.ReentrantLock;
public class FairLockExample {
// 公平锁参数设为true
private static final ReentrantLock fairLock = new ReentrantLock(true);
// 非公平锁参数设为false(默认)
private static final ReentrantLock unfairLock = new ReentrantLock(false);
private static int sharedResource = 0;
public static void main(String[] args) throws InterruptedException {
System.out.println("========== 公平锁测试 ==========");
testFairLock();
Thread.sleep(2000);
System.out.println("\n========== 非公平锁测试 ==========");
testUnfairLock();
}
// 测试公平锁
private static void testFairLock() throws InterruptedException {
Thread[] threads = new Thread[10];
long startTime = System.currentTimeMillis();
// 创建10个线程
for (int i = 0; i < 10; i++) {
final int threadId = i;
threads[i] = new Thread(() -> {
for (int j = 0; j < 3; j++) {
fairLock.lock();
try {
sharedResource++;
Thread.sleep(10); // 模拟业务操作
System.out.println("公平锁 - 线程" + threadId + " 第" + j + "次获取锁,当前值: " + sharedResource);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
fairLock.unlock();
}
}
});
threads[i].start();
}
// 等待所有线程完成
for (Thread thread : threads) {
thread.join();
}
long fairTime = System.currentTimeMillis() - startTime;
System.out.println("公平锁执行总耗时: " + fairTime + "ms");
}
// 测试非公平锁
private static void testUnfairLock() throws InterruptedException {
Thread[] threads = new Thread[10];
long startTime = System.currentTimeMillis();
// 创建10个线程
for (int i = 0; i < 10; i++) {
final int threadId = i;
threads[i] = new Thread(() -> {
for (int j = 0; j < 3; j++) {
unfairLock.lock();
try {
sharedResource++;
Thread.sleep(10); // 模拟业务操作
System.out.println("非公平锁 - 线程" + threadId + " 第" + j + "次获取锁,当前值: " + sharedResource);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
unfairLock.unlock();
}
}
});
threads[i].start();
}
// 等待所有线程完成
for (Thread thread : threads) {
thread.join();
}
long unfairTime = System.currentTimeMillis() - startTime;
System.out.println("非公平锁执行总耗时: " + unfairTime + "ms");
}
}
更直观的演示案例
import java.util.concurrent.locks.ReentrantLock;
public class FairLockDemonstration {
private static final ReentrantLock lock = new ReentrantLock(true); // 公平锁
public static void main(String[] args) {
// 创建5个线程,观察获取锁的顺序
for (int i = 1; i <= 5; i++) {
new Thread(new Task("任务" + i)).start();
}
// 稍微等待,让线程按顺序启动
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 主线程也参与竞争
lock.lock();
try {
System.out.println("主线程获取了锁");
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
static class Task implements Runnable {
private final String name;
Task(String name) {
this.name = name;
}
@Override
public void run() {
// 每个任务尝试获取锁3次
for (int i = 0; i < 3; i++) {
lock.lock();
try {
System.out.println(name + " - 第" + (i+1) + "次获取锁,执行中...");
Thread.sleep(100); // 模拟工作
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
}
自定义公平锁实现(简单版本)
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class CustomFairLock {
// 使用ReentrantLock实现公平锁
private final ReentrantLock lock = new ReentrantLock(true);
private final Condition notEmpty = lock.newCondition();
private int[] buffer = new int[10];
private int count = 0;
private int putIndex = 0;
private int takeIndex = 0;
// 生产者方法
public void produce(int value) {
lock.lock();
try {
while (count == buffer.length) {
notEmpty.await();
}
buffer[putIndex] = value;
putIndex = (putIndex + 1) % buffer.length;
count++;
System.out.println(Thread.currentThread().getName() + " 生产了: " + value + ",当前数量: " + count);
notEmpty.signalAll();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
// 消费者方法
public int consume() {
lock.lock();
int value;
try {
while (count == 0) {
notEmpty.await();
}
value = buffer[takeIndex];
takeIndex = (takeIndex + 1) % buffer.length;
count--;
System.out.println(Thread.currentThread().getName() + " 消费了: " + value + ",当前数量: " + count);
notEmpty.signalAll();
return value;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return -1;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
CustomFairLock buffer = new CustomFairLock();
// 创建多个生产者和消费者
for (int i = 0; i < 5; i++) {
final int producerId = i;
new Thread(() -> {
for (int j = 0; j < 3; j++) {
buffer.produce(producerId * 10 + j);
}
}, "生产者" + i).start();
}
for (int i = 0; i < 5; i++) {
new Thread(() -> {
for (int j = 0; j < 3; j++) {
buffer.consume();
}
}, "消费者" + i).start();
}
}
}
公平锁与非公平锁的区别
| 特性 | 公平锁 | 非公平锁 |
|---|---|---|
| 获取锁顺序 | 先来先得 | 允许插队 |
| 性能 | 相对较慢(需要维护队列) | 相对较快 |
| 公平性 | 保证公平 | 不保证公平 |
| 适用场景 | 需要公平性的场景 | 对性能要求高的场景 |
| 实现机制 | 基于FIFO队列 | 基于CAS操作 |
运行结果对比(示例)
========== 公平锁测试 ==========
公平锁 - 线程0 第0次获取锁,当前值: 1
公平锁 - 线程0 第1次获取锁,当前值: 2
公平锁 - 线程0 第2次获取锁,当前值: 3
公平锁 - 线程1 第0次获取锁,当前值: 4
...
公平锁执行总耗时: 412ms
========== 非公平锁测试 ==========
非公平锁 - 线程3 第0次获取锁,当前值: 31
非公平锁 - 线程3 第1次获取锁,当前值: 32
...
非公平锁执行总耗时: 289ms
- 公平锁:严格按照线程请求的顺序获取锁,但性能相对较差
- 非公平锁:允许线程插队,性能较好但可能导致某些线程"饿死"
- 使用建议:除非有特殊需求,一般推荐使用非公平锁(默认)
- 实现方式:公平锁使用FIFO队列保证顺序,非公平锁使用CAS原子操作
这个案例展示了公平锁的基本使用方法和特性,您可以根据实际需求选择合适的锁类型。