专业的JAVA编程教程与资源

网站首页 > java教程 正文

并发篇:一网打尽 Java 中的 8 种 ‘锁’ 事

temp10 2025-05-15 20:58:17 java教程 2 ℃ 0 评论

并发篇:一网打尽 Java 中的 8 种 ‘锁’ 事

最近在开发项目中遇到了资源同步的问题,导致服务器卡顿,优化的时候使用了锁的机制。在 Java 中,锁(Lock)是实现并发控制的重要机制,它可以控制多个线程对共享资源的访问。在 Java 中,有多种类型的锁可以使用,每种锁都有其适用的场景和优劣点。本文将介绍 Java 中的 8 种常见锁,包括 synchronized、ReentrantLock、ReentrantReadWriteLock、StampedLock、LockSupport、Semaphore、CountDownLatch 和 CyclicBarrier,并给出相应的 Java 代码示例。


并发篇:一网打尽 Java 中的 8 种 ‘锁’ 事

大家好,这里是互联网技术学堂,如果你有兴趣,那就点赞、关注、分享吧。

按照锁的特性和设计来划分,分为如下几类:

1、公平锁/非公平锁

2、可重入锁

3、独享锁/共享锁

4、互斥锁/读写锁

5、乐观锁/悲观锁

6、分段锁

7、偏向锁/轻量级锁/重量级锁

8、自旋锁(java.util.concurrent包下的几乎都是利用锁)

synchronized

synchronized 是 Java 中最常用的锁之一,它是一种内置锁,可以用来实现原子操作和保护临界区。synchronized 的使用方式很简单,只需要在方法或代码块前加上 synchronized 关键字即可。

public synchronized void addCount(){
    count++;
}

ReentrantLock

ReentrantLock 是一种可重入锁,它与 synchronized 类似,但是提供了更多的灵活性和功能,比如可以设置公平锁和非公平锁、可中断锁、可限时锁等。ReentrantLock 必须在 finally 块中释放锁。

ReentrantLock lock = new ReentrantLock();

public void addCount(){
    lock.lock();
    try{
        count++;
    } finally {
        lock.unlock();
    }
}

ReentrantReadWriteLock

ReentrantReadWriteLock 是一种读写锁,它可以同时允许多个线程读共享资源,但只允许一个线程写共享资源。它通过分离读锁和写锁来提高并发性能,读写锁的使用方式与 ReentrantLock 类似。

ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
ReadWriteLock.ReadLock readLock = rwl.readLock();
ReadWriteLock.WriteLock writeLock = rwl.writeLock();

public void read(){
    readLock.lock();
    try{
        // 读操作
    } finally {
        readLock.unlock();
    }
}

public void write(){
    writeLock.lock();
    try{
        // 写操作
    } finally {
        writeLock.unlock();
    }
}

StampedLock

StampedLock 是 Java 8 新增的一种锁,它是一种乐观锁,可以提高读操作的并发性能。StampedLock 支持三种锁模式:写锁、悲观读锁和乐观读锁,它们的使用方式与 ReentrantReadWriteLock 类似。


StampedLock sl = new StampedLock();

public void read(){
    long stamp = sl.tryOptimisticRead();
    // 读操作
    if(!sl.validate(stamp)){
        stamp = sl.readLock();
        try{
            // 读操作
        } finally {
            sl.unlockRead(stamp);
        }
    }
}

public void write(){
    long stamp = sl.writeLock();
    try{
        // 写操作
    } finally {
        sl.unlockWrite(stamp);
    }
}

LockSupport

LockSupport 是 Java 中提供的另一种锁机制,它可以用来挂起和恢复线程的执行,类似于 wait() 和 notify() 方法。LockSupport 提供了 park() 和 unpark() 方法来挂起和恢复线程的执行。

Thread thread = new Thread(() -> {
    // 线程执行前
    LockSupport.park(); // 挂起线程
    // 线程执行后
});

thread.start();
LockSupport.unpark(thread); // 恢复线程执行

Semaphore

Semaphore 是一种计数信号量,它可以控制同时访问某个共享资源的线程数。Semaphore 可以被看作是一种权限机制,只有获得许可证的线程才能访问共享资源。

Semaphore semaphore = new Semaphore(10); // 最多允许 10 个线程访问共享资源

public void accessResource() throws InterruptedException {
    semaphore.acquire(); // 获取许可证
    try{
        // 访问共享资源
    } finally {
        semaphore.release(); // 释放许可证
    }
}

CountDownLatch

CountDownLatch 是一种同步工具,它可以让一个线程等待多个线程完成后再继续执行。CountDownLatch 维护了一个计数器,当计数器的值变为 0 时,等待线程就可以继续执行。


CountDownLatch latch = new CountDownLatch(10); // 计数器的初始值为 10

public void doTask(){
    // 执行任务
    latch.countDown(); // 计数器减 1
}

public void await() throws InterruptedException {
    latch.await(); // 等待计数器变为 0
}

CyclicBarrier

CyclicBarrier 是一种同步工具,它可以让多个线程在指定的屏障点处等待,直到所有线程都到达后再一起继续执行。CyclicBarrier 维护了一个计数器和一个屏障点,当计数器的值变为 0 时,所有等待的线程都可以继续执行。

CyclicBarrier barrier = new CyclicBarrier(10); // 计数器的初始值为 10

public void doTask() throws InterruptedException, BrokenBarrierException {
    // 执行任务
    barrier.await(); // 等待其他线程到达屏障点
}

public void reset(){
    barrier.reset(); // 重置屏障点和计数器
}

以上就是 Java 中的 8 种常见锁,它们各有优缺点,可以根据具体的场景选择适合的锁来实现并发控制。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表