# Java并发编程之锁机制
# 1. synchronized 关键字
synchronized
是Java提供的最简单、最常用的锁机制。它可以用来同步方法或同步代码块,确保同一时间只有一个线程能访问指定资源。
# 示例:
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 特点:
- 锁对象:方法上使用
this
作为锁对象,静态方法使用类的Class对象作为锁。 - 自动释放:当线程离开同步代码块或方法时,自动释放锁。
- 性能较低:由于每个进入同步块的线程都需要获取锁,可能导致性能瓶颈。
# 2. ReentrantLock
ReentrantLock
是java.util.concurrent.locks
包下的锁实现,功能比synchronized
更丰富。它支持公平锁、可中断锁、尝试锁等功能。
# 示例:
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 特点:
- 手动加锁和解锁:使用
lock()
和unlock()
进行加锁和解锁,确保在finally
中释放锁,避免死锁。 - 公平锁:可以通过构造函数指定公平性,使等待时间最长的线程优先获取锁。
ReentrantLock lock = new ReentrantLock(true); // 公平锁
1
# 3. ReadWriteLock
ReadWriteLock
通过读写分离来提高性能。多个线程可以同时读,但只有一个线程可以写,读写是互斥的。
# 示例:
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteCounter {
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private int count = 0;
public void increment() {
lock.writeLock().lock();
try {
count++;
} finally {
lock.writeLock().unlock();
}
}
public int getCount() {
lock.readLock().lock();
try {
return count;
} finally {
lock.readLock().unlock();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 特点:
- 读锁可以允许多个线程同时读取数据。
- 写锁只能允许一个线程修改数据。
# 4. StampedLock
StampedLock
是Java 8引入的一种改进的锁机制。相比ReadWriteLock
,它更灵活,支持乐观读锁,以提高并发性能。
# 示例:
import java.util.concurrent.locks.StampedLock;
public class StampedCounter {
private final StampedLock lock = new StampedLock();
private int count = 0;
public void increment() {
long stamp = lock.writeLock();
try {
count++;
} finally {
lock.unlockWrite(stamp);
}
}
public int getCount() {
long stamp = lock.tryOptimisticRead();
int currentCount = count;
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try {
currentCount = count;
} finally {
lock.unlockRead(stamp);
}
}
return currentCount;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 特点:
- 乐观读锁:减少锁的开销,可以允许无锁读取操作。
- 如果读锁读取期间没有写操作发生,性能会大幅提升。
# 5. Condition
Condition
配合ReentrantLock
使用,用于线程间通信。它允许线程在等待某个条件时释放锁,直到条件满足后再重新获取锁。
# 示例:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BoundedBuffer {
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final Object[] items = new Object[100];
private int putIndex, takeIndex, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
notFull.await();
}
items[putIndex] = x;
if (++putIndex == items.length) putIndex = 0;
count++;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
notEmpty.await();
}
Object x = items[takeIndex];
if (++takeIndex == items.length) takeIndex = 0;
count--;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 特点:
await()
:让线程等待条件满足并释放锁。signal()
或signalAll()
:通知一个或多个等待的线程重新获得锁。
# 总结
synchronized
适用于简单的线程同步。ReentrantLock
提供更灵活的锁机制和更好的性能。ReadWriteLock
适合读多写少的场景。StampedLock
在读操作较多时提供更好的性能。Condition
则适用于更加复杂的线程间协作。