java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java重入锁线程同步

Java使用重入锁实现线程同步的示例代码

作者:Katie。

在多线程环境中,为保证对共享资源的安全访问,常用的同步手段是 synchronized 关键字,但 synchronized 存在局限,本项目旨在通过示例演示如何使用 ReentrantLock 实现线程同步,替代 synchronized,并展示其高级功能,需要的朋友可以参考下

一、项目背景详细介绍

在多线程环境中,为保证对共享资源的安全访问,常用的同步手段是 synchronized 关键字。但 synchronized 存在以下局限:

Java 5 引入了更强大的 java.util.concurrent.locks 包,其中的 ReentrantLock(可重入锁)在功能和性能上均优于内置锁。它提供:

本项目旨在通过示例演示如何使用 ReentrantLock 实现线程同步,替代 synchronized,并展示其高级功能,如超时尝试获取锁、公平策略和中断响应。

二、项目需求详细介绍

基本互斥访问

超时获取锁

可中断锁获取

公平锁与非公平锁

锁状态监控

示例应用

配置可控

文档与示例

三、相关技术详细介绍

java.util.concurrent.locks.ReentrantLock

Condition 接口

锁监控与诊断

中断与超时

多线程测试

四、实现思路详细介绍

SharedResource 类设计

void safeIncrement() { lock.lock(); try { /* 更新共享计数 */ } finally { lock.unlock(); } }
boolean trySafeIncrement(long timeout, TimeUnit unit) { if (lock.tryLock(timeout, unit)) { try { ... } finally { lock.unlock(); } } else { /* 超时逻辑 */ } }
void interruptibleAccess() throws InterruptedException { lock.lockInterruptibly(); try { ... } finally { lock.unlock(); } }

公平与非公平锁对比

监控锁状态

多线程测试

文档示例

/*
 * =====================================================
 * File: SharedResource.java
 * 共享资源类,使用 ReentrantLock 实现多种同步策略
 * =====================================================
 */
package com.example.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class SharedResource {
    private int counter = 0;
    private final ReentrantLock lock;
    private final Condition notZero;

    /**
     * 构造函数:可指定是否公平锁
     */
    public SharedResource(boolean fair) {
        this.lock = new ReentrantLock(fair);
        this.notZero = lock.newCondition();
    }

    /**
     * 基本互斥:安全地递增 counter
     */
    public void safeIncrement() {
        lock.lock();
        try {
            counter++;
            System.out.printf("%s incremented to %d%n",
                Thread.currentThread().getName(), counter);
            notZero.signalAll();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 带超时尝试获取锁的递增
     */
    public boolean trySafeIncrement(long timeout, TimeUnit unit) {
        boolean acquired = false;
        try {
            acquired = lock.tryLock(timeout, unit);
            if (acquired) {
                counter++;
                System.out.printf("%s timed increment to %d%n",
                    Thread.currentThread().getName(), counter);
                notZero.signalAll();
                return true;
            } else {
                System.out.printf("%s failed to acquire lock in %d %s%n",
                    Thread.currentThread().getName(), timeout, unit);
                return false;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.printf("%s interrupted while waiting%n",
                Thread.currentThread().getName());
            return false;
        } finally {
            if (acquired) lock.unlock();
        }
    }

    /**
     * 可中断地获取锁并等待 counter > 0 后消费
     */
    public int interruptibleConsume() throws InterruptedException {
        lock.lockInterruptibly();
        try {
            while (counter == 0) {
                System.out.printf("%s waiting for counter > 0%n",
                    Thread.currentThread().getName());
                notZero.await();
            }
            counter--;
            System.out.printf("%s consumed to %d%n",
                Thread.currentThread().getName(), counter);
            return counter;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 监控方法:打印当前锁状态
     */
    public void printLockStatus() {
        System.out.printf("Lock held by thread: %s, holdCount=%d, queuedThreads=%d%n",
            lock.isLocked() && lock.isHeldByCurrentThread()
                ? Thread.currentThread().getName()
                : "other",
            lock.getHoldCount(),
            lock.getQueueLength());
    }
}


/*
 * =====================================================
 * File: LockDemo.java
 * 演示:多线程调用 SharedResource 不同方法
 * =====================================================
 */
package com.example.lock;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class LockDemo {
    public static void main(String[] args) throws InterruptedException {
        SharedResource fairResource = new SharedResource(true);
        SharedResource unfairResource = new SharedResource(false);

        ExecutorService exec = Executors.newFixedThreadPool(6);
        CountDownLatch startLatch = new CountDownLatch(1);
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failCount = new AtomicInteger(0);

        // 创建 2 个常规增量任务
        for (int i = 0; i < 2; i++) {
            exec.submit(() -> {
                await(startLatch);
                fairResource.safeIncrement();
            });
        }

        // 创建 2 个带超时尝试锁任务
        for (int i = 0; i < 2; i++) {
            exec.submit(() -> {
                await(startLatch);
                if (fairResource.trySafeIncrement(500, TimeUnit.MILLISECONDS)) {
                    successCount.incrementAndGet();
                } else {
                    failCount.incrementAndGet();
                }
            });
        }

        // 创建 2 个可中断消费任务
        for (int i = 0; i < 2; i++) {
            exec.submit(() -> {
                await(startLatch);
                try {
                    unfairResource.interruptibleConsume();
                } catch (InterruptedException e) {
                    System.out.printf("%s interrupted%n",
                        Thread.currentThread().getName());
                }
            });
        }

        // 启动所有任务
        startLatch.countDown();

        // 等待一段时间后中断消费任务
        Thread.sleep(1000);
        exec.shutdownNow();
        exec.awaitTermination(5, TimeUnit.SECONDS);

        System.out.printf("TryLock successes: %d, failures: %d%n",
            successCount.get(), failCount.get());
    }

    private static void await(CountDownLatch latch) {
        try {
            latch.await();
        } catch (InterruptedException ignored) {}
    }
}

代码详细解读

SharedResource

LockDemo

使用 ExecutorService 启动 6 个线程:

项目详细总结

本示例通过 ReentrantLock 展示了:

项目常见问题及解答

为何要在 finallyunlock()
避免在执行过程中抛出异常导致锁未释放,进而引发死锁。

tryLock 获不到锁后还能重试吗?
可以在代码中判断失败后循环调用,或结合退避机制重试。

公平锁性能更差吗?
是的,公平锁会增加上下文切换成本,一般在需要严格顺序时使用,否则推荐默认非公平锁。

lockInterruptibly 如何正确处理中断?
调用方法需声明 throws InterruptedException,在捕获后可执行清理逻辑或直接结束任务。

如何监控生产环境中的锁竞争?
利用 lock.getQueueLength() 和日志定期采集,或结合 APM 工具监控线程等待情况。

扩展方向与性能优化

Condition 多队列
使用多个 Condition 实现更精细的等待/唤醒控制,例如生产者—消费者的 notFull / notEmpty

锁分段
对大数据结构进行分段加锁(类似 ConcurrentHashMap),降低锁粒度提升并发度。

公平性调优
在高并发场景下考虑非公平锁与超时重试结合,避免严格公平带来的吞吐下降。

锁剥离
当只有读操作时,可使用 ReadWriteLock 切换到无阻塞读锁,提高并发读性能。

可视化诊断
集成到监控平台或定制 Web 界面,实时展示锁争用、队列长度和线程等待图。

以上就是Java使用重入锁实现线程同步的示例代码的详细内容,更多关于Java重入锁线程同步的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文