I’m creating a game that uses multiple AppStates.
All is perfect, but there is only an issue… when I close the game (with Escape key), the frame isn’t visible but the process is still running in background. Why?
I’m not using other threads.
I call:
inputManager.clearMappings();
in the app initialization to remove the default mappings because I want to override them in the AppStates, so I created another listener: when I press Escape it calls first app.stop() and then cleanup() to cleanup the AppState.
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.151-b12 mixed mode):
"Timer-0" #23 prio=5 os_prio=0 tid=0x0000000016488800 nid=0x17d8 in Object.wait(
) [0x0000000016eff000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Unknown Source)
at java.util.TimerThread.mainLoop(Unknown Source)
- locked <0x00000000f0220fb8> (a java.util.TaskQueue)
at java.util.TimerThread.run(Unknown Source)
"DestroyJavaVM" #20 prio=5 os_prio=0 tid=0x00000000028d0800 nid=0x162c waiting o
n condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"TimerQueue" #18 daemon prio=5 os_prio=0 tid=0x00000000163e4800 nid=0xc7c waitin
g on condition [0x0000000019aef000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000f0f5c818> (a java.util.concurrent.lock
s.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(Unknown Source)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject
.await(Unknown Source)
at java.util.concurrent.DelayQueue.take(Unknown Source)
at javax.swing.TimerQueue.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
"D3D Screen Updater" #17 daemon prio=7 os_prio=1 tid=0x00000000163e4000 nid=0x94
0 in Object.wait() [0x00000000199ef000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at sun.java2d.d3d.D3DScreenUpdateManager.run(Unknown Source)
- locked <0x00000000f0f60258> (a java.lang.Object)
at java.lang.Thread.run(Unknown Source)
"AWT-Windows" #12 daemon prio=6 os_prio=0 tid=0x0000000015d2c800 nid=0xfa0 runna
ble [0x0000000016c0f000]
java.lang.Thread.State: RUNNABLE
at sun.awt.windows.WToolkit.eventLoop(Native Method)
at sun.awt.windows.WToolkit.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
"Java2D Disposer" #10 daemon prio=10 os_prio=2 tid=0x0000000015d29000 nid=0xc50
in Object.wait() [0x0000000016a0f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000f0e02c48> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
- locked <0x00000000f0e02c48> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
at sun.java2d.Disposer.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x000000001455c000 nid=0x10e4 ru
nnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x0000000014501000 nid=0x189
0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x00000000144fc000 nid=0x18d
0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x00000000144f8000 nid=0x1588 r
unnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000144f3000 nid=0x1828
waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x00000000144e8800 nid=0xb94 in Objec
t.wait() [0x000000001522f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
- locked <0x00000000f0f40c98> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x00000000029bc800 nid=0xe64
in Object.wait() [0x000000001512e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Unknown Source)
at java.lang.ref.Reference.tryHandlePending(Unknown Source)
- locked <0x00000000f0f3f798> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
"VM Thread" os_prio=2 tid=0x00000000144c6000 nid=0x1530 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000028e6000 nid=0x1304 runn
able
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000028e8000 nid=0xd4c runna
ble
"VM Periodic Task Thread" os_prio=2 tid=0x000000001459a000 nid=0x1858 waiting on
condition
JNI global references: 502
Heap
PSYoungGen total 14336K, used 9580K [0x00000000f0000000, 0x00000000f100000
0, 0x0000000100000000)
eden space 12288K, 61% used [0x00000000f0000000,0x00000000f075f068,0x00000000f
0c00000)
from space 2048K, 99% used [0x00000000f0e00000,0x00000000f0ffc278,0x00000000f1
000000)
to space 2048K, 0% used [0x00000000f0c00000,0x00000000f0c00000,0x00000000f0e
00000)
ParOldGen total 32768K, used 5962K [0x00000000d0000000, 0x00000000d200000
0, 0x00000000f0000000)
object space 32768K, 18% used [0x00000000d0000000,0x00000000d05d29b0,0x0000000
0d2000000)
Metaspace used 18249K, capacity 18541K, committed 18688K, reserved 106496
0K
class space used 2128K, capacity 2202K, committed 2304K, reserved 1048576K
The Timer-0 thread and the DestroyJavaVM threads aren’t daemon.
I think that the Timer-0 thread is associate to a Timer or not?
But I haven’t any Timer in my code…
IIRC, Timers start their threads on construction. Is this Timer constructed (i.e. new Timer()) or declared (i.e. Timer t;)?
If this Timer is constructed and thus indeed running, you can close it by calling Timer#cancel() or Timer#purge() (docs).
Edit: quote from docs:
… By default, the task execution thread does not run as a daemon thread, so it is capable of keeping an application from terminating. If a caller wants to terminate a timer’s task execution thread rapidly, the caller should invoke the timer’s cancel method.
The issue was the Timer initialization…
From this day i’ll hate Timers.
I used the timer to do some things and then I’ve eliminated that code, but I forgot to delete the Timer scheduler = new Timer().
Well just a rule of thumbs. Every single time I encountered this issue it was a thread cleanup issue. It always is.
And yes, a java Timer spawns a thread.