diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/lock/LockUtil.java b/hutool-core/src/main/java/cn/hutool/core/thread/lock/LockUtil.java
index 61a0fdcfc..f63d5c9c5 100644
--- a/hutool-core/src/main/java/cn/hutool/core/thread/lock/LockUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/thread/lock/LockUtil.java
@@ -1,6 +1,7 @@
package cn.hutool.core.thread.lock;
import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -140,4 +141,75 @@ public class LockUtil {
public static Lock getLazySegmentLock(int segments, Object key) {
return SegmentLock.lazyWeakLock(segments).get(key);
}
+
+
+ /**
+ * 下面 tryLock 和 lock 静态方法和辅助类LockStat 实现锁的自动加锁和解锁的封装
+ * 使用方法如下
+ *
+ * Lock myLock = new ReentrantLock();
+ *
+ * // 尝试获取锁,并设置超时时间
+ * try (LockStat lockStat = LockUtils.tryLock(myLock, 5, TimeUnit.SECONDS)) {
+ * if (lockStat.isLocked()) {
+ * // Critical section - lock acquired successfully
+ * doSomethingCritical();
+ * } else {
+ * // Handle case where lock was not acquired
+ * handleLockTimeout();
+ * }
+ * } // Lock 会自动释放
+ *
+ * // 获取锁,不设置超时时间
+ * try (LockStat lockStat = LockUtils.lock(myLock)) {
+ * // Critical section - lock is guaranteed to be acquired
+ * doSomethingCritical();
+ * } // Lock 会自动释放
+ *
+ *
+ */
+ public static LockStat tryLock(Lock lock, long timeout, TimeUnit timeUnit) {
+ boolean tryLock = false;
+ try {
+ tryLock = lock.tryLock(timeout, timeUnit);
+ } catch (InterruptedException e) {
+ tryLock = false;
+ }
+ return new LockStat(lock, tryLock);
+ }
+
+ public static LockStat tryLock(Lock lock) {
+ boolean tryLock = lock.tryLock();
+ return new LockStat(lock, tryLock);
+ }
+
+ public static LockStat lock(Lock lock) {
+ lock.lock();
+ return new LockStat(lock, true);
+ }
+
+ public static class LockStat implements AutoCloseable {
+ private final Lock lock;
+ private final boolean isLocked;
+
+ public LockStat(Lock lock, boolean isLocked) {
+ this.lock = lock;
+ this.isLocked = isLocked;
+ }
+
+ public Lock getLock() {
+ return lock;
+ }
+
+ public boolean isLocked() {
+ return isLocked;
+ }
+
+ @Override
+ public void close() {
+ if (isLocked) {
+ lock.unlock();
+ }
+ }
+ }
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/thread/lock/LockUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/thread/lock/LockUtilTest.java
new file mode 100644
index 000000000..2b72798aa
--- /dev/null
+++ b/hutool-core/src/test/java/cn/hutool/core/thread/lock/LockUtilTest.java
@@ -0,0 +1,228 @@
+package cn.hutool.core.thread.lock;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.concurrent.*;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * LockUtil单元测试类
+ */
+class LockUtilTest {
+
+ private Lock testLock;
+ private ExecutorService executor;
+
+ @BeforeEach
+ void setUp() {
+ testLock = new ReentrantLock();
+ executor = Executors.newCachedThreadPool();
+ }
+
+ /**
+ * 测试tryLock方法 - 立即获取锁成功
+ */
+ @Test
+ void testTryLockSuccess() {
+ try (LockUtil.LockStat lockStat = LockUtil.tryLock(testLock)) {
+ assertTrue(lockStat.isLocked(), "tryLock应该成功获取锁");
+ assertSame(testLock, lockStat.getLock(), "返回的锁应该是传入的锁对象");
+ }
+ }
+
+ /**
+ * 测试tryLock方法 - 立即获取锁失败
+ */
+ @Test
+ void testTryLockFail() throws InterruptedException, ExecutionException, TimeoutException {
+ CountDownLatch latch = new CountDownLatch(1);
+ CountDownLatch releaseLatch = new CountDownLatch(1);
+
+ // 在另一个线程中先获取锁
+ Future future = executor.submit(() -> {
+ testLock.lock();
+ latch.countDown(); // 通知已获取锁
+ try {
+ releaseLatch.await(); // 等待释放信号
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } finally {
+ testLock.unlock();
+ }
+ return null;
+ });
+
+ // 等待另一个线程获取锁
+ latch.await();
+
+ // 尝试获取锁应该失败
+ try (LockUtil.LockStat lockStat = LockUtil.tryLock(testLock)) {
+ assertFalse(lockStat.isLocked(), "tryLock应该获取锁失败");
+ assertSame(testLock, lockStat.getLock(), "返回的锁应该是传入的锁对象");
+ }
+
+ // 释放第一个线程的锁
+ releaseLatch.countDown();
+ future.get(1, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 测试tryLock方法 - 带超时时间成功获取锁
+ */
+ @Test
+ void testTryLockWithTimeoutSuccess() {
+ try (LockUtil.LockStat lockStat = LockUtil.tryLock(testLock, 1, TimeUnit.SECONDS)) {
+ assertTrue(lockStat.isLocked(), "tryLock应该在超时时间内成功获取锁");
+ assertSame(testLock, lockStat.getLock(), "返回的锁应该是传入的锁对象");
+ }
+
+ }
+
+ /**
+ * 测试tryLock方法 - 带超时时间获取锁超时
+ */
+ @Test
+ void testTryLockWithTimeoutFail() throws InterruptedException, ExecutionException, TimeoutException {
+ CountDownLatch latch = new CountDownLatch(1);
+ CountDownLatch releaseLatch = new CountDownLatch(1);
+
+ // 在另一个线程中先获取锁并持有较长时间
+ Future future = executor.submit(() -> {
+ testLock.lock();
+ latch.countDown(); // 通知已获取锁
+ try {
+ releaseLatch.await(2, TimeUnit.SECONDS); // 持有锁2秒
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } finally {
+ testLock.unlock();
+ }
+ return null;
+ });
+
+ // 等待另一个线程获取锁
+ latch.await();
+
+ // 尝试在短时间内获取锁应该超时失败
+ long startTime = System.currentTimeMillis();
+ try (LockUtil.LockStat lockStat = LockUtil.tryLock(testLock, 100, TimeUnit.MILLISECONDS)) {
+ assertFalse(lockStat.isLocked(), "tryLock应该因超时而获取锁失败");
+ assertSame(testLock, lockStat.getLock(), "返回的锁应该是传入的锁对象");
+ }
+ long elapsedTime = System.currentTimeMillis() - startTime;
+ assertTrue(elapsedTime >= 100 && elapsedTime < 500, "应该在大约100毫秒后超时");
+
+ // 释放第一个线程的锁
+ releaseLatch.countDown();
+ future.get(3, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 测试tryLock方法 - 处理InterruptedException
+ */
+ @Test
+ void testTryLockInterrupted() throws InterruptedException {
+ CountDownLatch startLatch = new CountDownLatch(1);
+ CountDownLatch lockAcquiredLatch = new CountDownLatch(1);
+ CountDownLatch testCompleteLatch = new CountDownLatch(1);
+
+ // 先在主线程获取锁
+ testLock.lock();
+
+ Future future = executor.submit(() -> {
+ startLatch.countDown();
+ try (LockUtil.LockStat lockStat = LockUtil.tryLock(testLock, 5, TimeUnit.SECONDS)) {
+ return lockStat.isLocked();
+ } finally {
+ testCompleteLatch.countDown();
+ }
+ });
+
+ // 等待子线程开始执行
+ startLatch.await();
+ Thread.sleep(100); // 确保子线程已开始等待锁
+
+ // 中断子线程
+ future.cancel(true);
+
+ // 释放锁
+ testLock.unlock();
+
+ // 等待子线程完成
+ testCompleteLatch.await(1, TimeUnit.SECONDS);
+
+ try {
+ assertTrue(future.isCancelled() || !future.get(100, TimeUnit.MILLISECONDS),
+ "被中断的线程应该获取锁失败");
+ } catch (ExecutionException | TimeoutException e) {
+ // 预期的异常,因为线程被中断
+ assertTrue(future.isCancelled(), "线程应该被取消");
+ }
+ }
+
+ /**
+ * 测试lock方法 - 成功获取锁
+ */
+ @Test
+ void testLockSuccess() {
+ try (LockUtil.LockStat lockStat = LockUtil.lock(testLock)) {
+ assertTrue(lockStat.isLocked(), "lock应该成功获取锁");
+ assertSame(testLock, lockStat.getLock(), "返回的锁应该是传入的锁对象");
+ }
+
+ }
+
+
+ /**
+ * 测试LockStat的close方法只在获取锁成功时才释放锁
+ */
+ @Test
+ void testLockStatCloseOnlyWhenLocked() {
+ try (LockUtil.LockStat lockStat = LockUtil.tryLock(testLock)) {
+ assertTrue(lockStat.isLocked(), "重入锁获取锁成功");
+ } // close方法不应该调用unlock,因为没有获取到锁
+
+
+ // 测试获取锁成功的情况
+ try (LockUtil.LockStat lockStat = LockUtil.tryLock(testLock)) {
+ assertTrue(lockStat.isLocked(), "应该获取锁成功");
+ } // close方法应该调用unlock
+
+ }
+
+ /**
+ * 测试多次close调用的安全性
+ */
+ @Test
+ void testMultipleClose() {
+ LockUtil.LockStat lockStat = LockUtil.lock(testLock);
+ assertTrue(lockStat.isLocked(), "应该获取锁成功");
+
+ }
+
+ /**
+ * 测试嵌套使用try-with-resources
+ */
+ @Test
+ void testNestedTryWithResources() {
+ ReentrantLock reentrantLock = new ReentrantLock();
+
+ try (LockUtil.LockStat outerLockStat = LockUtil.lock(reentrantLock)) {
+ assertTrue(outerLockStat.isLocked(), "外层应该获取锁成功");
+
+ // 由于ReentrantLock支持重入,内层也应该成功
+ try (LockUtil.LockStat innerLockStat = LockUtil.lock(reentrantLock)) {
+ assertTrue(innerLockStat.isLocked(), "内层应该获取锁成功(重入)");
+ }
+
+ // 外层锁仍应该有效
+ assertTrue(outerLockStat.isLocked(), "外层锁仍应该有效");
+ }
+
+ }
+
+}