浅谈Java之多线程锁处理
一、基本介绍
在Java中,多线程环境下的锁处理是一个非常重要的话题,因为它涉及到线程安全和数据一致性。Java提供了多种锁机制来帮助开发者控制对共享资源的访问。
二、锁处理方式
内置锁(synchronized):
synchronized
关键字可以用来修饰方法或者代码块,确保同一时间只有一个线程可以执行该段代码。- 对于方法,它锁定的是调用该方法的对象实例。
- 对于代码块,它锁定的是括号内指定的对象。
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
重入锁(ReentrantLock):
ReentrantLock
是java.util.concurrent.locks
包下的一个类,提供了与synchronized
关键字类似的同步功能,但是更加灵活。- 它支持尝试非阻塞地获取锁、可中断地获取锁、超时获取锁等。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private final Lock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
}
读写锁(ReadWriteLock):
ReadWriteLock
允许多个读操作同时进行,但写操作是独占的。- 适用于读操作远多于写操作的场景。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Counter {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private int count = 0;
public void increment() {
rwLock.writeLock().lock();
try {
count++;
} finally {
rwLock.writeLock().unlock();
}
}
public int getCount() {
rwLock.readLock().lock();
try {
return count;
} finally {
rwLock.readLock().unlock();
}
}
}
显式锁(Locks):
- Java还提供了其他类型的锁,如
StampedLock
,它是一种乐观锁,提供了一种更细粒度的锁定机制。
条件变量(Condition):
- 与锁配合使用,用于线程间的协调,允许一个或多个线程等待某些条件成立。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class BoundedBuffer {
private final Object[] items = new Object[100];
private int putPtr, takePtr, count;
private final ReentrantLock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
notFull.await();
}
items[putPtr] = x;
if (++putPtr == items.length) putPtr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
notEmpty.await();
}
Object x = items[takePtr];
if (++takePtr == items.length) takePtr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
原子变量(Atomic Variables):
- 对于简单的计数器或累加器,可以使用
java.util.concurrent.atomic
包下的原子变量,如AtomicInteger
,它们利用底层硬件的原子指令来保证操作的原子性。
import java.util.concurrent.atomic.AtomicInteger;
public class Counter {
private final AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
三、注意事项
- 锁的粒度:锁的粒度越细,性能越好,但实现起来越复杂。
- 锁的顺序:避免死锁,确保所有线程获取锁的顺序一致。
- 锁的持有时间:尽量减少锁持有的时间,以减少等待时间。
- 锁的公平性:
ReentrantLock
允许设置公平锁,以确保线程获取锁的顺序。