The best way to exit a program is to do it cleanly and this means closing everything you have opened. If you don't do this then things like buffered data may get lost and some hardware devices may get left in an indeterminate state. Having said that leJOS, Java and the underlying operating system take defensive steps to try and ensure that things are cleaned up as much as is possible when a program terminates as a result devices will be closed and there will be no memory leak. However this does mean that for instance some sensors may be left in an active state (since there is no generic way to cleanly close down say an i2c sensor), depending on the hardware this may or not be an issue.
So if you want to have some sort of emergency exit button, then I suggest that a way to do that is to have a boolean called say shutdown in a class that monitors the escape key. When the key is pressed then the boolean is set to true. have all of your threads check this boolean and if they find it set to true have them clean up any devices they "own" and close them etc. As a final emergency step have the thread that monitors the escape key call System.exit a short period after setting the boolean to true. That way your threads get chance to close down cleanly, but if they don't do so the program will exit anyway. You could try and close things from your "exit thread" but in general it is usually better to have a single thread deal with a resource including closing it down, trying to close devices etc. that may be in use from another thread can often cause problems that are hard to debug and may cause issues with the hardware. There are lots of variations on this sort of theme, but the above works reasonably well in most cases, you might also want to consider using the Java thread interrupt system:https://docs.oracle.com/javase/tutorial ... rrupt.html
which may help if your threads make use of blocking calls (but then again it probably won't!).