【问题标题】:Behavior of finally block if thread interrupted如果线程中断,finally 块的行为
【发布时间】:2014-04-01 09:36:08
【问题描述】:

我正在学习 java 中的线程。根据description of finally block in an Oracle tutorial

注意:如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。 同样,如果执行 try 或 catch 代码的线程被中断或杀死,即使应用程序作为一个整体继续运行,finally 块也可能不会执行。

所以我尝试在try catch块中中断一个线程并检查finally是否在下一个类中执行。但是根据程序的输出,finally 块被执行。有人可以解释发生了什么吗?

package com.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


 public class TestLock{
     public static void main(String[] args) throws InterruptedException {
          MyThread lockT= new MyThread();
         Thread t= new Thread(lockT); 
         t.setName("TempThread1"); 
         t.start();
         Thread.sleep(1000); 
         t.interrupt();
    }
 }

 class MyThread implements Runnable {
        Lock lock;
        public MyThread() {
            lock= new ReentrantLock();
        }
        @Override
        public void run() { 
            try {
                if(lock.tryLock()){
                         Thread.sleep(5000);
                     while (!Thread.currentThread().isInterrupted()) { 
                            System.out.println("My thread name is   "+ Thread.currentThread().getName());        
                     }                  
                }
            } catch (Exception e) {
                e.printStackTrace();                
            }finally{
                System.out.println("finally ");
                lock.unlock();
            }           

        }


    }

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    这里的规则是:may not execute,这并不意味着it will not execute

    所以基本上规则是说:不要依赖 finally 块将被执行,我们不提供这样的保证。

    【讨论】:

    • 在这种情况下,我们如何依赖 Lock 接口,因为我们通常最终实现内部锁定,这种情况会引发死锁。(对不起,我知道这不是讨论论坛,只是想了解的行为最后并锁定界面)
    • 嗯,我认为如下:如果你不中断线程,你可以依赖这个。
    • 谢谢你的回答,因为我没有使用太多的中断。
    • 彼得,请注意,OP 问题中的引用根本不是来自规范或官方 Javadoc。它来自一个教程,这使它只是一个描述性说明。这不是我第一次看到人们混淆规范来源的教程。
    • @MarkoTopolnik 好点,谢谢,Marko。好的,是的,我的笔记也是基于它是规范来源/文本的假设。但如果不是……我们到底在讨论什么?那么问题和答案都无关紧要,我猜。
    【解决方案2】:

    我知道这是一个旧线程,但我想介绍一个线程被中断并且最终不执行的情况:这是示例代码:

    public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        test.LockWork();
    }public void LockWork() {
        WithLock withLock = new WithLock();
        Thread t1 = new Thread(() -> {
            withLock.produce();
        });
        Thread t2 = new Thread(() -> {
            withLock.consume();
        }); 
        ExecutorService service= Executors.newCachedThreadPool(new WithLockThreadFactory());
        Future f1=service.submit(t1);
        Future f2=service.submit(t2);
        //f1.cancel(true);
        try {
            System.out.println("-------------------------------------sleeping now-------------------------------------");
            Thread.sleep(3000);
            System.out.println("-------------------------------------Intereputing Producer-------------------------------------");
            f1.cancel(true);
            service.shutdown();
            Thread.sleep(1000);
            System.out.println("is Producer done: "+f1.isDone());
            service.awaitTermination(1, TimeUnit.DAYS);
            System.out.println("is Consumer done: "+f2.isDone());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Ending Program");
    }
    

    现在有我的线程工厂:

    public class WithLockThreadFactory implements ThreadFactory {
    private int counter;
    
    public WithLockThreadFactory() {
        this.counter = 1;
    }
    
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r, "WithLockThreadFactoryThread " + counter);
        counter++;
        return t;
    }
    

    现在 WithLock 类:

    public class WithLock {
    ReentrantLock lock = new ReentrantLock(true);
    LinkedList<Integer> linkedList = new LinkedList<>();
    Condition isEmpty = lock.newCondition();
    Condition isFull = lock.newCondition();
    int limit = 10;
    volatile int interruptCounter = 0;
    
    public void produce() {
        System.out.println("WithLock.produce() Name: " + Thread.currentThread().getName());
        try {
            int value = 1;
            while (true) {
                lock.lockInterruptibly();
                if (limit == linkedList.size()) {
                    System.out.println("acquiring lock in produce");
                    isEmpty.await(3000, TimeUnit.MILLISECONDS);
                }
                linkedList.add(value % limit);
                System.out.println("value added to list: " + value % limit);
                value++;
                isFull.signal();
                System.out.println("notifiedy lock in produce");
                lock.unlock();
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.out.println("I was interupted Producer");
            interruptCounter++;
            System.out.println("interruptCounter value :" + interruptCounter);
        } finally {
            lock.unlock();
            System.out.println("Finally Unlocked Producuer");
        }
        System.out.println("Ending things now: Producer");
    }
    
    public void consume() {
        System.out.println("WithLock.consume() Name: " + Thread.currentThread().getName());
        try {
            while (true) {
                lock.lockInterruptibly();
                // no use as poll doesn't throw an exception if the queue is
                // empty
                if (linkedList.size() == 0) {
                    System.out.println("acquiring lock in consume");
                    isFull.await(3000, TimeUnit.MILLISECONDS);
                    if (interruptCounter > 2) {
                        break;
                    }
                }
                System.out.println("removing element from queue: " + linkedList.poll());
                isEmpty.signal();
                System.out.println("notifiedy lock in consume");
                lock.unlock();
                Thread.sleep(1000);
                if (interruptCounter != 0) {
                    interruptCounter++;
                }
            }
        } catch (InterruptedException e) {
            System.out.println("I was Interupted Consumer");
        } finally {
            lock.unlock();
            System.out.println("Finally Unlocked Consumer");
        }
        System.out.println("Ending things now: Consume");
    }
    

    }

    这是控制台的输出:

        -------------------------------------sleeping now-------------------------------------
    WithLock.produce() Name: WithLockThreadFactoryThread 1
    WithLock.consume() Name: WithLockThreadFactoryThread 2
    value added to list: 1
    notifiedy lock in produce
    removing element from queue: 1
    notifiedy lock in consume
    acquiring lock in consume
    value added to list: 2
    notifiedy lock in produce
    removing element from queue: 2
    notifiedy lock in consume
    acquiring lock in consume
    value added to list: 3
    notifiedy lock in produce
    removing element from queue: 3
    notifiedy lock in consume
    -------------------------------------Intereputing Producer-------------------------------------
    I was interupted Producer
    interruptCounter value :1
    acquiring lock in consume
    is Producer done: true
    removing element from queue: null
    notifiedy lock in consume
    acquiring lock in consume
    Finally Unlocked Consumer
    Ending things now: Consume
    is Consumer done: true
    Ending Program
    

    这是我觉得很有趣并想分享的东西。我在JAVA8中试过了。

    【讨论】:

      【解决方案3】:

      如果JVM退出...

      尝试System.exit() 呼叫...

      【讨论】:

      • 感谢您的回答,但我知道如果 JVM 存在,它最终不会调用,但我正在寻找 try catch 块中的线程中断
      • 好的,那么,在linux中,当你调用kill时,会创建信号,当我在try-finally块中有Thread.sleep(10000);时单击Eclipse中的“Terminate”按钮时,最终不会执行。 ..
      • ...尽管整个应用程序仍在继续...我错过了,有趣...
      【解决方案4】:

      首先,Oracle 的教程是描述性的,而不是规范性的。您的报价绝不应被视为行为规范。

      线程可以在执行finally 块时被中断,在这种情况下,所述finally 块可能确实无法完成。但是,这完全在您的控制之下,您始终可以编写这样的finally,它不会受到这种情况的影响。

      请放心,finally 块不会被跳过,因为它的 try 块中出现了常规的 InterruptedException

      如果一个线程被重复stop()ped,那么确保finally块的执行将更加困难。

      【讨论】:

      • 根据Java doc给出的,如果try catch中发生中断,那么finally可能无法运行,如果finally运行并且发生中断,那么代码将无法执行任何操作。
      • 现在我明白你错在哪里了:你引用了 Oracle 的 tutorial,它不是 Javadoc 并且 不是规范。我在回答中写的内容是 100%。
      猜你喜欢
      • 1970-01-01
      • 2011-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多