Opus1217
Opus1217

Reputation: 743

Is it ok to not "join" interrupted threads?

I have a card game app where the "Droid" hand has to choose among multiple discards to optimize its hand. So I am threading the possible discard choices and then calculating the hand valuation. I use two different approaches to hand valuation; one is exhaustive but can be very expensive, and the other is heuristic and very fast. I switch from the exhaustive approach to the heuristic approach once the computation time exceeds 500ms. I do this by starting the threads over the possible discards, and then also starting a sleep thread. When it finishes sleeping, it interrupts the other threads and I then rerun them with the heuristic approach.

All of this is working fine.But in checking for an interrupted thread in the join loop, I immediately throw an InterruptedException so that the caller knows to rerun the calculation. In doing so, I don't ever join the other interrupted threads. Is that a resource leak, or will the other threads be cleaned up eventually?

Code snippets follow: Starting my threads:

    for (Card disCard : cardsWithAdded) {
        CardList cards = new CardList(cardsWithAdded);
        cards.remove(disCard);

        testHand[iThread] = new ThreadedHand(this.hand.getRoundOf(), cards, disCard, this.method, isFinalTurn); //creates new hand with replaced cards
        t[iThread] = new Thread(threadGroup,testHand[iThread]);
        t[iThread].start(); //calls meldAndEvaluate
        iThread++;
    }

Interrupting them in the sleep thread:

        public void run() {
        final long sleepStartTime = System.currentTimeMillis();
        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
            // if interrupted, this means the other threads finished their work before the sleep ended
            return;
        }
        threadGroup.interrupt(); //interrupt the other calculation threads
    }

Check for interruption in the calculation thread (in a loop):

        if (Thread.interrupted()) {
            throw new InterruptedException();
        }

Setting a flag in run:

        public void run()  {
        threadStart = System.currentTimeMillis();
        wasThreadInterrupted = false;
        try {
            this.meldAndEvaluate(this.method, EasyComputerPlayer.this , this.isFinalTurn);
        } catch (InterruptedException e) {
            //just break out of this thread
            threadStop = System.currentTimeMillis();
            wasThreadInterrupted = true;
        }
        threadStop = System.currentTimeMillis();
    }

And the join where I break at the first interrupted thread:

         for (int iThread=0; iThread < this.numThreads; iThread++) {
        try {
            t[iThread].join();
        } catch (InterruptedException e) {
            throw new InterruptedException(String.format("%s-%s: findBestHandFinish interrupted in join()...",FiveKings.APP_TAG,Thread.currentThread().getName()));
        }
        //can only test this flag after we've rejoined the thread to this one
        if (testHand[iThread].wasThreadInterrupted()) throw new InterruptedException(String.format("After join: Thread %s shows was-interrupted - throwing exception", t[iThread].getName()));

Upvotes: 1

Views: 83

Answers (2)

Solomon Slow
Solomon Slow

Reputation: 27190

The call t.join() doesn't do anything except wait for thread t to die. It doesn't do anything at all to thread t.

Upvotes: 0

Stephen C
Stephen C

Reputation: 719281

Joining the threads is neither necessary ... or sufficient to prevent resource leaks.

In reality:

  • The thread stack is eligible for reclamation when the thread has terminated1. If the thread does not respond appropriately to the interrupt (i.e. by terminating itself) then you have a resource leak.

  • The Thread object is eligible for reclamation after the thread has terminated AND there are no reachable references to the object. But leakage of the Thread object is a simple memory leak, not a resource leak in the normal sense.


1 - A thread terminates when the run() method terminates, either normally (by returning) or abnormally (as a result of the propagation of an unchecked exception).

Upvotes: 4

Related Questions