Articles

One Thing I Really Hate About the JVM

Whilst I think the [[Java Virtual Machine]] is generally speaking a fantastic piece of kit, there is one thing that I really hate about it: I can’t stop threads!!!

Sure, there’s a method called Thread.stop() … but it’s deprecated. There’s even a whole article devoted to why it should be deprecated.

Great.  That’s just great.  So, how do I stop a thread?

Perhaps some context would be helpful.  I use an automated marking script that goes through each student’s submission, runs their code and compares it against correct output.  It’s really useful, and catches lots of subtle mistakes they make.

Now, the problem of course is that student code doesn’t always terminate. That means I need a way to timeout their code within my marking system, and just report an error.

Which brings me back to the problem of stopping threads.  After the timeout, I must stop the thread executing the student’s code — otherwise, my system is quickly going to overload as I plough more and more student submissions into it.  A really good discussion on the right way to stop threads in Java can be found here.  The discussion revolves around interrupting running threads via Thread.interrupt().  From my perspective, the salient quote is:

Now if the thread has started, and was not in a sleep() or wait() method, then calling interrupt() on it does not throw an exception.

The issue is that, essentially, to stop a thread via this mechanism it must spend time in a sleep() or wait() method.  Now, I can try to force this to be true by putting it into a library method which the students must use.  But, usually, their code still gets stuck in an infinite loop which doesn’t call sleep or wait.

Problem? Indeed.  My solution, whilst not exactly pretty, does seem to work most of the time — but, it relies on using the deprecated method Thread.stop().  You can get the code here.

The moral of the story seems to be: don’t stop people from doing useful things because they might do bad things. Sure, the reasoning behind why Thread.stop() was deprecated is very sensible — but, it forgets that there are valid use cases where it can be used without causing harm and, furthermore, is necessary for those use cases to work.

UPDATE: I should add that sandboxing is not really an issue here.  Each student’s code already runs as a separate JVM process as an unpriviledged user.  However, there are many tests executed for each student which are currently controlled via threads.

UPDATE: An alternative implementation which uses wait() and notify() instead of Thread.sleep() can be found here.  However, it doesn’t appear to be as realiable as the original … and if anyone can point out the bug(s), that would be appreciated!!!

UPDATE: Another alternative implementation which uses ProcessBuilder can be found here. This seems to work pretty well.

23 comments to One Thing I Really Hate About the JVM

  • Anon

    You could try not using Java.

  • Well, the student’s code is in Java (not my control), and I need to interface with it. But, you’re right … I could deal with timeouts at a higher level by killing processes … it’s just annoying I can’t do it from Java.

  • Dan

    Spawn another process instead of using threads. After the timeout expires, you can kill it.

  • Erik

    Yup, I agree with Dan. If you’re going to tear something down, you should use a process so that it can’t create a mess in your own process.

    How can you trust the results of the remaining students submissions if they’re running in a JVM that’s in an undefined state?

  • dherring

    Few languages or even operating systems get this right. It is very hard to stop a process that is accessing shared resources (i.e. a thread and memory) without leaving a mess in the shared resources.

    For an interesting read, look into PCLSRing.

  • Mark

    Use processes. It’s not just Java – threads are what processes were with a co-operative scheduler, and are therefore for code you trust. Stomping on a thread causes makes it impossible to reason about the state of your process – you’ll end up with opened critical sections, orphaned handles and file descriptors, invalid callbacks and leaked memory. And unlike normal catastrophic failure, your process will then try to continue. Just don’t do it.

    See also http://blogs.msdn.com/b/oldnewthing/archive/2003/12/09/55988.aspx

  • Jamie

    Yeah, I agree with the others. Threads are designed for code that you trust well enough to share the same address space. If the language were C, would you just load it up as a .so and let rip? It should be run in its own process, preferably as an unprivileged user with strict ulimits. (Student code may not be deliberately malicious, but I remember our multithreading course got pretty tedious when 200 students all started forkbombing our shared servers… and of course stopping just one thread won’t help you much there either.)

    So no, you don’t have a valid use case.

  • Jeremy

    You stop threads by ending the condition of the while in your thread. It’s really quite simple. You get really unpredictable behaviour if you try and stop executing mid call.

    while (threadIsRunning)
    {
    doSomething();
    }

    then eventually just threadIsRunning = false… Voala, thread is stopped.

  • tef

    as mentioned before

    if you are running untrusted code (i.e student code) you should be running it in a separate process. there is nothing to stop a buggy piece of student code killing your supervisory thread.

    ‘ it’s just annoying I can’t do it from Java.’

    the reason is simply – if you need to kill something you should be running a process. threads are for things you co-operate with. things that co-operate don’t need to kill each other

  • You will go round and round and round in circles trying to find the “right way” to stop a thread. There is none. You *must* set a flag in a shared data structure, and let the thread stop itself. “But what if the thread is doing X?” isn’t a valid question, if X is something you’ve not thought of, or can’t control. There’s a reason the stop() method is deprecated – it’s because you have no control over the state of the program afterwards. Even if things looks like they’re working, there’ll be one point in your stopped code where the program goes wrong. In summary, don’t do it :)

  • Neebat

    Do you have the student’s source code? If so, you can modify it to be sure it stops when you tell it to. Insert a considerStopping() method call at the top of each block and after each statement.

    This might still be possible with a decompiler.

  • Stopping threads in Java is dead simple: you just need to understand and properly use thread interrupt flags. Using Thread.interrupt(), Thread.isInterrupted(), and Thread.interrupted(), you can determine when you need to stop, from within your thread, and exit your loop, or whatever else it is you’re doing.

    Notice that sleep() throws an InterruptedException. In the example of interrupting a sleeping thread, you catch this interruption, and re-interrupt your thread, or terminate whatever you’re doing. If you’re using IO, as of 1.4 you can use NIO, whose IO operations are interruptable. Otherwise, if you’re using standard Java IO, you can just check your thread’s interrupt status on each read() iteration.

    Thread.stop() was deprecated for a reason: killing an in-progress thread can have unintended consequences. Killing a thread may result in unclosed files, or improperly closed sockets or whatever else. Using thread interrupts, Java allows you to shut down your threads in a predictable way, allowing you to choose how best to stop whatever it is you’re doing.

  • Java is usually a great language. Then you get stuff like this. Why the hell.

  • reisi

    @Luke:

    You should go an read the docs on Thread#stop() and the history of how threads have been implemented.

    @Dave:

    As others have pointed out, it might very well be that using out-of-process execution is the only right choice here. Otherwise you might expose students code to problems they would not in any sane situation face.

    Your StopTimerMethod#exec(int,Method,Object,Object…) is not exactly a programming pearl. You should read up on Object#notify and Object#wait. Also, there are OSS examples of “executing method with timeout”, see JUnit4.

    Final note: If you really insist on not doing this properly (out-of-process) load-time AOP weaving MIGHT be able to solve this.. But that’s even more complicated that using eclipse-junit launcher like -solution.

  • Hi,

    I had a similar problem in my research project. I solved it by transforming the bytecode I do not trust (in your case, the students’ bytecode) so to automatically insert checkpoints. These checkpoints are placed in strategic points (e.g., before each back-edge) and verify if the thread can continue working or if it must be stopped.

    If you want to have a look on the source code, it is available online here: http://code.google.com/p/testful/source/browse/testful/src/testful/coverage/stopper/#

    Please note that I’m working on the new version of the framework, which has several improvements in many areas (including this one). I never thought this feature would be required also in “normal” projects… maybe we can re-elaborate that part a little and release it as standalone project… let me know!


    Matteo

  • mu

    Think you misunderstand interrupt(). Its meant to interrupt a blocking call such as sleep() but its not meant to stop a thread. Ofcourse its often used to do that by first setting the threads “running” flag to false and then setting the interrupt flag to make sure the thread will notice that flag has changed – but this still requires the threads cooperation. Threads are all part of the same process and considered to be friendly and coorperative. If you are running “hostile” code that does not share your apps signalling mechanism to stop then threads are probably not the right thing.

  • Thanks for all the comments folks!!!! Looks like I should investigate using processes …

    reisi said:

    Your StopTimerMethod#exec(int,Method,Object,Object…) is not exactly a programming pearl.

    Thanks :) The key is it seems to work fairly consistently on my machine. I had explored using interrupt() to interupt the sleep(), but that didn’t seem to work very well at all. I haven’t explored using wait() and notify(), but I’ll definitely give that a go …

  • Hey Reisi,

    Ok, here’s an updated version using Thread.wait() and Thread.notify(). However, it’s not as reliable as the original … for some reason, it randomly generates exceptions related to java.lang.ThreadDeath and I cannot figure why.

    Comments?

  • reisi

    For proper using notify/wait you must:
    – wait in a loop for a condition (see method documentation about spurious wakeups)

    and you should:
    – synchronize on this for the whole run()
    – drop volatile on finished
    – replace whole implementation with Callable, FutureTask composed impl [1]

    I haven’t ever seen a ThreadDeath, but that is a symptom of you using Thread#stop(), documented right there. If you are testing with code that a) might runaway b) might come near the timeout with total running time you are always prone to seeing this exception.

    The email I got about you having problems with “java.lang.Thread(Ljava/lang/String;)V” missing or something is outdated? That would be interesting..

    Also I’ve been thinking about this problem you have. Does it really matter if a single student code has a never-ending control flow? Couldn’t you just run them on a thread pool with all threads having Thread#setDaemon(boolean) set to true, and merely check if the thread has finished after the timeout, and react to that fact as it is; no cleanup code.

    Some out-of-process running is always going to be needed; if you look available solutions for c/c++ courses (boss was one, perhaps?) they all run stuff out-of-process. This is simply because OS is so great at cleaning up after processes.

    Also, I’d like to recommend reading Java Concurrency In Practice (jcip). It covers all these topics with “how to do”, “how not to do” kind of examples and also discusses Thread#stop().

    1 = If you’d use standard, common java.util.concurrent “primitives” you could later on for example run all your students code concurrently (using thread context classloaders could give you the same isolation as process, see osgi and google “classworlds” and “onejar”).

    With standard components, your current class would be separated to two, “reflection callable” and the logic to throw a callable to an (wrapped) executorservice (to detect when it has actually been started), and the logic to detect timeouts/runaways.

    Also note that I’m not Doug Lea and might be misleading you by mistake all the time along :)

  • Michael B

    Yes if you want to have human intervention you can always go in and ‘fix’ the code to be well behaving. But that requires human intervention every time. The only sensible solution to avoid this has long been (and still is?) is spawning processes and killing them. However spawning JVM’s is traditionally slow(startup-time) and resource intensive(overhead in cpu, memory, etc) Also you probably want more control then just start and stop.

    What your trying to achieve is program isolation and there has been research into this and even an JSR http://www.jcp.org/en/jsr/detail?id=121

    “It offers data protection guarantees, enables clean application termination, and provides a good foundation for per-application resource usage accounting.”

    “At the same time, there is no single prescribed way to implement isolates. Some implementations may equate an isolate with an operating system process. Others, much more scalable, will host multiple isolates in a single instance of the virtual machine. The latter can be viewed as a type-safe language kernel, just as, for example, UNIX is a kernel for programs developed in C.”
    http://java.sun.com/developer/technicalArticles/Programming/mvm/

    failing a good implementation of isolates you can run in debug and bytecode inject ‘if(Thread.interrupted()) throw …’ + hot code swapping and get somewhere if really all the controll you need is stopping.

  • You know this could be case where Aspects would be useful. Take the student’s code and then use the point cuts to add in some waits(), then your interrupt() method would be more likely to work. Still I think your point is valid, sometimes you just gotta and you live with the consequences.

  • Ran Biron

    Load the student code with a javaagent, inject a call to your method that checks if the process should be stopped or not. if so – throw some error and mark it. if you reach a second threshold, terminate the process or force all of statements to not execute.

    You can really do wonders when you start playing with code injection.

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>