有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程为什么java ReentrantLock不抛出InterruptedException?

我想在Java线程并发中创建竞争条件并创建死锁。 我使用ReentrantLock,但它不会抛出InterruptedException

现在是死锁,我使用lockinterruptablely,但它不会抛出InterruptedException,有人能告诉我为什么吗

  public class Test {

    public static void main(String[] args) throws InterruptedException {

        final Object o1 = new Object();
        final Object o2 = new Object();

        final ReentrantLock l1 = new ReentrantLock();
        final ReentrantLock l2 = new ReentrantLock();

        Thread t1 = new Thread() {
            public void run() {
                try {
                    l1.lockInterruptibly();
                    System.out.println("I am in t1 step 1 " + o1.toString());
                    Thread.sleep(1000);
                    l2.lock();
                    try {
                        System.out.println("I am in t1 step 2 " + o2.toString());
                    } finally {
                        l2.unlock();
                    }

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        Thread t2 = new Thread() {
            public void run() {
                try {
                    l2.lockInterruptibly();
                    System.out.println("I am in t2 step 1 " + o2.toString());
                    Thread.sleep(1000);
                    l1.lock();
                    try {
                        System.out.println("I am in t2 step 2 " + o1.toString());
                    } finally {
                        l1.unlock();
                    }
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
        };

        t1.start();
        t2.start();
        Thread.sleep(2000);
        t1.interrupt();
        t2.interrupt();
        t1.join();
        t2.join();

    }
}

共 (4) 个答案

  1. # 1 楼答案

    it doesn't throw InterruptedException, can any body tell me why?

    也许是因为ReentrantLock创建的目的是相互排斥

    任何时候,程序中的线程将互斥锁保持超过一小部分秒的时间,都是一种糟糕的代码气味

    使lock.lock()调用可中断将使所有使用它的程序复杂化:每个要锁定锁的地方,都必须为InterruptedException编写一个处理程序

    我的猜测(仅此而已)是,作者认为他们不应该让所有程序员都必须编写这些额外的中断处理程序,以便一些程序员可以在糟糕的设计中使用^{

  2. # 2 楼答案

    你的问题是,每个线程都试图获得两个锁

                    // Thread 1.
                    l1.lockInterruptibly();
                    // ....
                    l2.lock();
    
    
                    // Thread 2.
                    l2.lockInterruptibly();
                    // ....
                    l1.lock();
    

    因此,每个线程抓住一个锁,然后试图抓住另一个线程已经持有的锁。这叫做死锁

    您没有看到java.lang.InterruptedException,因为线程等待的锁(第二个)不是可中断的锁

    用以下方法解决此问题:

                    // Thread 1.
                    l1.lockInterruptibly();
                    // ....
                    l2.lockInterruptibly();
    
    
                    // Thread 2.
                    l2.lockInterruptibly();
                    // ....
                    l1.lockInterruptibly();
    
  3. # 3 楼答案

    可重入意味着已经持有锁的单个线程可以重新获取锁

    在您的例子中,有两个不同的线程正在创建

    这被称为重新进入锁定,类似于死锁和嵌套监视器锁定

    你可以通过线程t1来解决这个问题

                l1.lockInterruptibly();
                System.out.println("I am in t1 step 1 " + o1.toString());
                Thread.sleep(1000);
                l2.lockInterruptibly();
    

    在t2线中

                l2.lockInterruptibly();
                System.out.println("I am in t2 step 1 " + o2.toString());
                Thread.sleep(1000);
                l1.lockInterruptibly();
    
  4. # 4 楼答案

    这两个线程在以下行中处于死锁状态:l1.lock()l2.lock()。所以当你打断他们时,他们不会做出反应。如果用lockInterruptibly()替换所有lock()调用,则会出现异常

    编辑: 我准备了一个更简单的例子,可以根据您的需要生成竞争条件:

    public class Test {
    
        public static void main(String[] args) throws InterruptedException {
    
            final ReentrantLock l1 = new ReentrantLock();
            final Random rn = new Random();
    
            Thread t1 = new Thread() {
                public void run() {
                    try {
                        Thread.sleep(rn.nextInt(1000)); //wait 0-999 ms
                        l1.lockInterruptibly();
                        System.out.println("Thread 1 won");
                    } catch (InterruptedException e) {
                        System.out.println("Thread 1 interrupted");
                    }
                }
            };
    
            Thread t2 = new Thread() {
                public void run() {
                    try {
                        Thread.sleep(rn.nextInt(1000)); //wait 0-999 ms
                        l1.lockInterruptibly();
                        System.out.println("Thread 2 won");
                    } catch (InterruptedException e1) {
                        System.out.println("Thread 2 interrupted");
                    }
                }
            };
    
            t1.start();
            t2.start();
            Thread.sleep(2000);
            t1.interrupt();
            t2.interrupt();
            t1.join();
            t2.join();
    
        }
    }
    

    使用此代码,每次运行时,您都会随机获得两个输出中的一个:

    Thread 1 won
    Thread 2 interrupted
    

    或者

    Thread 2 won
    Thread 1 interrupted
    

    取决于生成的随机数