一起聊聊Java中13种锁的实现方式
背景介绍
在Java中使用锁是实现多线程同步的一种常用方式,也是保证程序并发安全的必要手段。本文将对Java中13种锁的实现方式进行详细讲解。
13种锁实现方式
1. synchronized关键字
synchronized
关键字是Java中最基本、最常用的锁实现方式。它通过获取对象的锁来控制对对象的访问,进而实现多线程的同步。
public synchronized void synchronizedMethod() {
// 需要同步的代码块
}
2. ReentrantLock
ReentrantLock
是Java中的另一种锁实现方式。它提供了比synchronized
更丰富的特性,比如可定时、可中断的锁请求,公平锁等。
private Lock lock = new ReentrantLock();
public void reentrantLockMethod() {
lock.lock();
try {
// 需要同步的代码块
} finally {
lock.unlock();
}
}
3. ReentrantReadWriteLock
ReentrantReadWriteLock
在读写操作需要频繁发生时可以提高性能,它是基于ReentrantLock
实现的。
private ReadWriteLock lock = new ReentrantReadWriteLock();
public void readMethod() {
lock.readLock().lock();
try {
// 读操作,多线程可以共享访问
} finally {
lock.readLock().unlock();
}
}
public void writeMethod() {
lock.writeLock().lock();
try {
// 写操作,只能有一个线程执行
} finally {
lock.writeLock().unlock();
}
}
4. StampedLock
StampedLock
是Java 8中引入的锁实现方式,比ReentrantReadWriteLock
性能更高。
private StampedLock lock = new StampedLock();
public void stampedLockMethod() {
long stamp = lock.readLock();
try {
// 读操作,多线程可以共享访问
} finally {
lock.unlockRead(stamp);
}
}
public void stampedWriteLockMethod() {
long stamp = lock.writeLock();
try {
// 写操作,只能有一个线程执行
} finally {
lock.unlockWrite(stamp);
}
}
5. Condition
Condition
是Java中的一种比较高级的线程同步方式,它可以协调一组线程的执行。例如,先执行线程A,在执行其它N个线程,最后再执行线程A。
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void conditionMethod() {
lock.lock();
try {
// 等待信号
condition.await();
// 唤醒后执行的代码块
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void signalMethod() {
lock.lock();
try {
// 发送信号
condition.signal();
// 继续执行后面的代码
} finally {
lock.unlock();
}
}
6. Semaphore
Semaphore
是Java中用来实现信号量机制的锁,可以控制对共享资源的访问线程数。
private Semaphore semaphore = new Semaphore(10);
public void method() {
try {
semaphore.acquire();
// 访问共享资源的代码块
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
7. CountDownLatch
CountDownLatch
是一个同步器,可以实现等待线程一组操作完成后再执行某个操作,比如等待多个线程处理完成后再执行某个操作。
private CountDownLatch countDownLatch = new CountDownLatch(5);
public void method() {
// 业务逻辑处理
countDownLatch.countDown();
}
public void joinMethod() {
try {
countDownLatch.await();
// 当countDownLatch的计数器减为0时执行的操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
8. CyclicBarrier
CyclicBarrier
也是一个同步器,它会等待所有线程都执行完成后再执行下一步操作,和CountDownLatch
类似,但是它可以重复使用。
private CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> {
// 所有线程执行完成后执行的操作
});
public void method() {
// 业务逻辑处理
cyclicBarrier.await();
}
9. LockSupport
LockSupport
是Java中一种基于线程的锁机制,可以控制线程的阻塞和唤醒。
public void parkMethod() {
LockSupport.park();
// 执行后续代码
}
public void unparkMethod() {
LockSupport.unpark(Thread.currentThread());
}
10. ThreadLocal
ThreadLocal
可以实现对线程中数据的隔离和独立访问,每个线程都能存储属于自己的数据。多线程访问同一个ThreadLocal
对象时,每个线程都是操作自己的数据,互不干扰。
private ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
public void method() {
threadLocal.set(1);
// 其它业务代码
threadLocal.get();
}
11. ReadWriteLock
ReadWriteLock
接口提供比synchronized
和ReentrantLock
提供更好的性能,多个线程可以同时进行读操作,但是写操作只能有一个线程执行。
private ReadWriteLock lock = new ReentrantReadWriteLock();
public void readMethod() {
lock.readLock().lock();
try {
// 读操作,多个线程可以共享访问
} finally {
lock.readLock().unlock();
}
}
public void writeMethod() {
lock.writeLock().lock();
try {
// 写操作,只能有一个线程执行
} finally {
lock.writeLock().unlock();
}
}
12. LongAdder
LongAdder
是Java 8中引入的一种高并发计数器,它可以减少多线程竞争,从而提高性能。
private LongAdder longAdder = new LongAdder();
public void increment() {
longAdder.increment();
}
public long sum() {
return longAdder.sum();
}
13. AtomicXXX
Java中提供了一系列AtomicXXX
类,它们通过原子操作实现了线程安全,比如AtomicInteger
。
private AtomicInteger atomicInteger = new AtomicInteger();
public void increment() {
atomicInteger.incrementAndGet();
}
public int get() {
return atomicInteger.get();
}
示例说明
示例一:ReentrantLock
比如在一个银行转账的场景中,假设有两个账户a和b,需要进行转账操作。在这个过程中,将a和b锁起来,防止其它线程的干扰,就可以使用ReentrantLock。
private ReentrantLock lock = new ReentrantLock();
private Map<String, Integer> accountMap = new HashMap<>();
public void transfer(String fromAccount, String toAccount, Integer amount) {
lock.lock();
try {
Integer fromMoney = accountMap.get(fromAccount);
Integer toMoney = accountMap.get(toAccount);
fromMoney -= amount;
toMoney += amount;
accountMap.put(fromAccount, fromMoney);
// 模拟延迟
Thread.sleep(100);
accountMap.put(toAccount, toMoney);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
示例二:Semaphore
比如在一个生产者-消费者的场景中,假设生产者最多创建10个商品,每个消费者可以消费1个商品。在这个过程中,生产者和消费者之间需要互相协调,防止生产者创建过多的商品,也防止消费者消费过多的商品,就可以使用Semaphore。
private Semaphore semaphore = new Semaphore(10);
public void producer() {
try {
semaphore.acquire();
// 业务代码:创建商品
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
public void consumer() {
try {
semaphore.acquire();
// 业务代码:消费商品
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
总结
Java中共有13种锁实现方式,从synchronized
到AtomicXXX
类,每种锁都有各自的优缺点。开发者在选择锁实现方式时需要结合实际场景,综合考虑其性能、复杂度等因素,才能选出最合适的锁实现方式。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一起聊聊Java中13种锁的实现方式 - Python技术站