coreJavare
coreJavare

Reputation: 1469

Behavior of finally block if thread interrupted

I am learning threading in java. As per the description of finally block in an Oracle tutorial:

Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.

So I tried to interrupt a thread in try catch block and check whether finally is executed in following class. But as per the output of the program, finally block is executed. Can someone explain what happened?

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();
            }           

        }


    }

Upvotes: 2

Views: 2149

Answers (4)

Kid101
Kid101

Reputation: 1470

I know it's a old thread but I'd like to present a situation where the threads get interrupted and doesn't execute finally: Here is the sample code:

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");
}

now There is my Thread Factory:

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;
}

now WithLock Class:

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");
}

}

and this is the output in the console:

    -------------------------------------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

This is something I found interesting and wanted to share. I tried it in JAVA8.

Upvotes: 1

Marko Topolnik
Marko Topolnik

Reputation: 200206

First and foremost, Oracle's tutorials are descriptive and not normative. Your quote should by no means be taken as specification of behavior.

The thread can be interrupted while executing the finally block, in which case the said finally block may indeed fail to complete. This is, however, fully under your control and you can always write such a finally which is not susceptible to this happening.

Rest assured that the finally block will not be skipped over due to a regular InterruptedException occurring within its try block.

If a thread is being repeatedly stop()ped, however, it will be harder to ensure the finally block executes.

Upvotes: 0

Betlista
Betlista

Reputation: 10547

If the JVM exits...

Try System.exit() call...

Upvotes: 0

peter.petrov
peter.petrov

Reputation: 39477

The rule here is saying: may not execute which does not mean it will not execute.

So basically the rule is saying: don't rely that the finally block will be executed, we don't provide such guarantees.

Upvotes: 4

Related Questions