0

I'm attempting to get my Java application to close, but threads are being left open.

When close is clicked using the default windows x button, everything shuts fine (probably due to EXIT_ON_CLOSE?)- but when I use a programmatic button, it hangs on thread.join().

Even worse, the window is disposed fine, so the user would think it's shut- yet there are several AWT threads that stay open. My main thread is waiting on a thread with an id of 20, but I have no idea how to get thread IDs.

Does anyone have any suggestions?

Here's my exit code:

public synchronized void stop() {
    running = false;
    frame.dispose();
    WindowEvent wev = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);
    Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(wev);
    try {
        if (server != null) {
            server.exit();
        }
        client.exit();
        thread.join();
        new Thread(){
            public void run() {
                System.exit(0);
            }
        }.start();
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        e.printStackTrace();
        System.exit(1);
    }
}

and here are the threads open post-exit:

threads-eclipse

and here's the contents of my run() method:

public void run() {
    requestFocus();
    while (running) {
        getTimer().tick();
        if (System.currentTimeMillis() - getTimer().getSecond() > 1000) {
            // every second, add a second, print fps and mod title with fps
            getTimer().accumulateSecond();
            //System.out.println(getTimer().returnFPS());
            frame.setTitle(title + "  |  " + getTimer().returnFPS());
            getTimer().resetTick();
            ticker++;
        }
        while (getTimer().getDelta() >= 1) {
            // every time delta goes greater than one, update and supertick
            update();
            getTimer().superTick();
        }
        if (getTimer().getFPS() > 100) {
            try {
                Thread.sleep(5);
            } catch (Exception e) {
                System.err.println("Sleeping failed: " + e);
            }
        } 
        render();
        if (ticker > 30) {
            ticker = 0;
            getTimer().hourTick();
        }

    }
    stop();
}
Nate
  • 31,017
  • 13
  • 83
  • 207
gossfunkel
  • 257
  • 2
  • 4
  • 13
  • moving the `System.exit(0)` temporary thread above `join()` works to close it completely, but I doubt it's thread-safe? – gossfunkel May 30 '13 at 22:39
  • please whats reason missing that here, could it be wrong, – mKorbel May 31 '13 at 06:57
  • Is the `run()` method you show in an *inner* `Thread` class within the same class as the `stop()` method above? Are there any other calls within `run()` that invoke `synchronized` methods? – Nate Jun 01 '13 at 22:06

1 Answers1

0

Update:

After seeing more of your code, I'm pretty sure your problem is that you are calling stop() (which is synchronized) from one thread. Inside stop(), you call thread.join(), which attempts to wait for the thread instance to finish its run() method. Setting the running flag causes run() to exit its while loop, but the last line of code in the method is another call to stop(). If this is the same stop() method you showed us, then you have a deadlock.

The stop() call inside your run() method will never be able to enter the method, because the first thread is still inside stop() and is waiting for run() to complete (which it never will, because it's waiting to be able to call and enter stop()). Deadlock.

You will have to remove the call to stop() from within run(), or find another way to rework your code.


I wouldn't worry about identifying particular thread IDs. Worry about letting all your threads complete properly.

First of all, Thread#join() does not stop a thread. It waits for it to finish. Something else you're doing must cause/allow the thread instance to complete its run() method.

The only thing I see that could possibly do this is setting

    running = false;

Is your thread object checking that flag inside its run() method? For example:

public void run() {
    while (isRunning()) {

        // do some work
        Thread.sleep(delay);
    }
}

where isRunning() would return you the value of the running variable?

Now, I can't say without seeing more of your code. However, you may have chosen to implement isRunning() like this:

public synchronized boolean isRunning() {
    return running;
}

If you did that, then there's a problem. The main thread will acquire the lock in the stop() method you showed us. Then it will get to the thread.join() call, at which point it starts waiting for the worker thread. If the worker thread then calls isRunning() which is synchronized on the same lock, then isRunning() will block, because the lock is already held by virtue of the main thread being inside stop().

The same basic problem could occur if the thread object is trying to call any other synchronized method from the class whose code you showed us.

Long story short, we'd need to see some more code (what is running in the thread represented by the thread variable). But, you may have reached a deadlock here.

Read more here about stopping a thread gracefully

Community
  • 1
  • 1
Nate
  • 31,017
  • 13
  • 83
  • 207
  • The `run()` method checks `running` directly, and yes, the whole thing is whiled right inside it. I believe it's waiting on some subthread to close, but I can't identify any. There aren't many synchronized methods about, not too many resources that could become unsynced. – gossfunkel May 31 '13 at 06:42
  • We can't help you unless you show us that code (the code that runs inside the `run()` method passed to the `thread` object). What you've shown is not enough to debug the problem, aside from the guess I already made. – Nate May 31 '13 at 07:57
  • 1
    @gossfunkel, if that's the same `stop()` method being called from `run()`, then that's your problem. `stop()` is `synchronized`, so `thread` will not be able to enter `stop()`, since another thread is already **inside** `stop()`, waiting at `thread.join()`. – Nate Jun 01 '13 at 20:59
  • sweet jesus, you're right. That was astonishingly stupid, terribly sorry! unfortunately, it's not solved the problem. – gossfunkel Jun 01 '13 at 21:55
  • Wait, I don't understand. Was it the same call to `stop()`? If so, then that's a problem. If you're still not seeing the thread die, then you **also** have another problem. But, since we can't see the definitions of your other methods, it's hard to say what **else** might be wrong. – Nate Jun 01 '13 at 21:59
  • It looks like I have another problem! I dare say I'll just need to use the fix I have right now, and solve it properly when I can identify the problem. – gossfunkel Jun 01 '13 at 22:05
  • @gossfunkel, please don't post questions and then decide you don't really need the solution. That wastes the time of people who take time to help you (for free). – Nate Jun 02 '13 at 02:22
  • The need is still there, but there is no rush for a solution to be found. Thanks very much for the help, I was just saying that it didn't fix it, and that I could wait out learning the fix in the long run if the answer isn't readily available now. – gossfunkel Jun 02 '13 at 07:50