Skip to content

Conversation

@chrisis58
Copy link

关于当前 ReentrantLock 就属于是可中断锁。 的论述,实际上 ReentrantLock#lock 方法也属于不可中断锁,所以直接使用类进行锁的分类可能不太合适。

我在区分了不同方法的区别的基础上,添加了一个简单的总结。

附录

代码演示
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo {
    
    static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        // -------------------------------------------------------
        // 不可中断的 lock()
        // -------------------------------------------------------
        System.out.println("=== 场景一:测试 lock() (不可中断) ===");
        testNonInterruptible();
        
        Thread.sleep(4000);  // 等待第一个测试结束
        System.out.println("\n-----------------------------------\n");

        // -------------------------------------------------------
        // 可中断的 lockInterruptibly()
        // -------------------------------------------------------
        System.out.println("=== 场景二:测试 lockInterruptibly() (可中断) ===");
        testInterruptible();
    }

    /**
     * 测试不可中断锁 lock()
     * 预期:线程被中断后不会醒来,必须等到拿到锁之后,才能发现自己被中断过。
     */
    public static void testNonInterruptible() throws InterruptedException {
        Thread threadA = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("【线程A】持有锁,准备睡 3 秒...");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("【线程A】释放锁");
                lock.unlock();
            }
        });

        Thread threadB = new Thread(() -> {
            System.out.println("【线程B】尝试获取锁 (lock())...");
            lock.lock();
            try {
                System.out.println("【线程B】成功获取锁");
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("【线程B】发现自己在等待期间被中断过");
                }
            } finally {
                lock.unlock();
            }
        });

        threadA.start();
        Thread.sleep(100);
        threadB.start();
        Thread.sleep(100);

        System.out.println("【主线程】向线程B发送中断信号...");
        threadB.interrupt();
    }

    /**
     * 测试可中断锁 lockInterruptibly()
     * 预期:线程收到中断信号后,立即抛出异常并放弃等待。
     */
    public static void testInterruptible() throws InterruptedException {
        Thread threadA = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("【线程A】持有锁,准备睡 3 秒...");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("【线程A】释放锁");
                lock.unlock();
            }
        });

        Thread threadB = new Thread(() -> {
            System.out.println("【线程B】尝试获取锁 (lockInterruptibly())...");
            try {
                lock.lockInterruptibly();
                try {
                    System.out.println("【线程B】拿到锁了 (这行信息不应该出现)");
                } finally {
                    lock.unlock();
                }
            } catch (InterruptedException e) {
                System.out.println("【线程B】捕获异常:阻塞被中断");
            }
        });

        threadA.start();
        Thread.sleep(100); 
        threadB.start();
        Thread.sleep(100); 

        System.out.println("【主线程】向线程B发送中断信号...");
        threadB.interrupt();
    }
}

代码的输出结果应该为:

=== 场景一:测试 lock() (不可中断) ===
【线程A】持有锁,准备睡 3 秒...
【线程B】尝试获取锁 (lock())...
【主线程】向线程B发送中断信号...
【线程A】释放锁
【线程B】成功获取锁
【线程B】发现自己在等待期间被中断过

-----------------------------------

=== 场景二:测试 lockInterruptibly() (可中断) ===
【线程A】持有锁,准备睡 3 秒...
【线程B】尝试获取锁 (lockInterruptibly())...
【主线程】向线程B发送中断信号...
【线程B】捕获异常:阻塞被中断
【线程A】释放锁

JDK 版本: java version "17.0.10" 2024-01-16 LTS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant