Snap method for Java console game - java

I've just put together one of my first full Java programs for practice. It is a simple snap game but I'm not happy with the method for the actual "Snap" condition. I may be being fussy but I wonder if there is something better someone could suggest?
public static boolean snap() {
Scanner response = new Scanner(System.in);
double compReflex = (Math.random() * (1000 - 250 + 1)) + 250;
long reflex = Math.round(compReflex);
long startTime = System.currentTimeMillis();
System.out.println("go");
response.nextLine();
if (System.currentTimeMillis() > startTime + reflex) {
System.out.println("I win");
response.close();
return false;
} else {
System.out.println(System.currentTimeMillis() - startTime);
System.out.println("Well done");
response.close();
return true;
}
}
The issue is I would like the else clause to happen immediately if a button was pressed and the if=True clause to happen automatically after the reflex delay if the button isn't pressed. At the moment enter has to be pressed and then the computer judges who had the shortest reaction time. Which isn't snap...
I looked at KeyListeners but they only seem to be available for UI's such as JSwing? I also looked at thread interruption but couldn't work out how to trigger a thread interrupt and then handle the exceptions with the correct program flow? Or is it is even possible?
I think it needs to be a multi-threaded solution but don't fully have a handle on concurrency/multi-threading yet so any really good learning resources appreciated in addition to solutions.

If the console API weren't so dreadfully old, you could simply do something like
try {
System.in.readLine(100, TimeUnit.MILLIS);
System.out.println("You win!");
} catch (InterruptedException e) {
System.out.println("Too slow!");
}
but unfortunately, the API to read from a console was defined in the very first release of the Java programming language, and not reworked since, so it doesn't allow reading with a timeout. If a thread reads from an InputStream, it won't stop reading until there is data, the InputStream itself signals an error, or the entire JVM exits.
So if you really want to do this, you'd need something like this:
public static void main(String[] args) {
var readerThread = new Thread(() -> {
try (var scanner = new Scanner(System.in)) {
scanner.nextLine();
gameOver(true);
}
});
readerThread.setDaemon(true); // this thread should not inhibit JVM termination
readerThread.start();
System.out.println("Go!");
sleep(500, TimeUnit.MILLISECONDS);
gameOver(false);
}
static void sleep(int duration, TimeUnit unit) {
try {
Thread.sleep(unit.toMillis(duration));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
synchronized static void gameOver(boolean victory) {
if (!over) {
System.out.println(victory ? "You win!" : "I win!");
over = true;
}
}
static boolean over;
A few things to note here:
Since the two threads race to gameOver, we need to ensure they don't both execute it. By making the method synchronized, we ensure that the threads will execute it after each other, and by setting a boolean, we can detect whether the other thread was faster.
everything is static because we can't cancel the reading thread. Granted, we could keep it running and reuse it for the next instance of the game, but it would eat any console input in the meantime (such as the answer to "do you want to try again?"), which is annoying. So I am not going to pretend that this solution is nice and reusable, and thus can make my life easier by making everything static.
the try-with-resources statement is a compact way to close a resource (such as a Scanner) once we are done with it.
the utility method for sleep is just to move the pointless, but required, catch block out of the main method, so the main method is easier to read.

Related

Is it okay to call the the method a try catch statement is in with the finally block

I made a switch case statement menu with one of the options being System.exit(0);. This is all surrounded by a try, finally that calls the method all of this is in. Would you guys not recommend this style of loop or am I all good?
public void Run() {
Scanner myObj = new Scanner(System.in);
int menuInput;
try {
System.out.println(" 1) call something\n"
+"2) quit");
menuInput = myObj.nextInt();
myObj.nextLine();
switch(menuInput) {
case 1:
something();
break;
case 2:
System.exit(0);
break;
}
}catch (Exeption e ){
System.out.println("Something went wrong.");
}finally{
Run();
}
}
No.
What you have here is an infinite recursion. Eventually you'd overflow the stack.
Use an actual loop instead:
while (true) {
try {
// ...
} catch (Exception e) {
// ...
}
}
And you almost never want to call System.exit. Just break the loop instead.
Is this legal code? Yes.
Is what you have there recommended? No.
If the method throws an exception it's likely recalling it will throw again. See the quote below.
Calling it again in a tight loop without attempting remedy, at least waiting a recovery and counting failures (3 strikes out?) will just end up in a tight loop of failure and stack overflow here.
So:
Can you identify errors that retrying may work and only retry on those?
You should almost certainly include some kind of 'back-off' wait before retry.
Always (always!) include a maximum retry number after which you accept failure.
In my experience the only kind of failure that may work on retry is 'service unavailable' meaning an intermittent outage.
It may not be relevant, but things like (say) invalid credentials aren't going to fix themselves and ideally you don't resubmit those. That's particularly because you end up locking the account and being in an even worse state and possibly causing issues for others using the valid credential...
The other scenario is (say) file not found and you're using the non-existence of a file as a way of polling for something.
That's a poor design pattern and is a misuse of exception handling.
You should strongly prefer to use some kind for existence check in those cases and not let routine activity get confused with exception handling of issues.
Also if you do retry log each attempt (it may be useful later to see whether things are running smoothly or getting delayed in retry scenarios even if the go through eventually). But always differentiate a 'Warning' when retrying and 'Error' when 'throwing in the towel' and failing.
public class Runner {
private static int MAX_RETRIES=3;
private static int BACK_OFF_MILLIS=30000;
public void Run() throws Exception,InterruptedException {
final int TRIES=3;//In reality may be configured.
int trycount=1;
for(;;){
try{
tryRun();
return;
}catch(Exception e){
String message=e.getMessage();
if(trycount>=MAX_RETRIES){
System.out.println("*FAILED*: "+e.getMessage());
throw e;
}
boolean retriable=true;
//Any tests for non-retriable exceptions here...
if(!retriable){
System.out.println("*FAILED*: non-retriable exception - "+e.getMessage());
throw e;
}
++trycount;
System.out.println("Warning: "+e.getMessage()+" retrying "+ trycount+" of "+TRIES);
try {
Thread.sleep(trycount*BACK_OFF_MILLIS);//Some kind of back-off...
}catch(InterruptedException ie){
System.out.println("*FAILED*: Interrupted. Aborting.");
throw ie;
}
continue;
}
}
}
public void tryRun() throws Exception{
//Real workload goes here!
}
}
NB: The back-off strategy here is very simplistic. When it comes to outages then it's usually recommended to implement a random element and an increasing back-off like 1 minute, 10 minutes, 25 minutes. But that's a topic in itself.
I'm not sure who really said but this popular quote seems relevant.
The definition of insanity is doing the same thing over and over again
and expecting different results

Java Thread seemingly skipping conditional statement [duplicate]

This question already has answers here:
Why doesnt this Java loop in a thread work?
(4 answers)
Closed 3 years ago.
For a recent library I'm writing, I wrote a thread which loops indefinitely. In this loop, I start with a conditional statement checking a property on the threaded object. However it seems that whatever initial value the property has, will be what it returns even after being updated.
Unless I do some kind of interruption such as Thread.sleep or a print statement.
I'm not really sure how to ask the question unfortunately. Otherwise I would be looking in the Java documentation. I have boiled down the code to a minimal example that explains the problem in simple terms.
public class App {
public static void main(String[] args) {
App app = new App();
}
class Test implements Runnable {
public boolean flag = false;
public void run() {
while(true) {
// try {
// Thread.sleep(1);
// } catch (InterruptedException e) {}
if (this.flag) {
System.out.println("True");
}
}
}
}
public App() {
Test t = new Test();
Thread thread = new Thread(t);
System.out.println("Starting thread");
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
t.flag = true;
System.out.println("New flag value: " + t.flag);
}
}
Now, I would presume that after we change the value of the flag property on the running thread, we would immediately see the masses of 'True' spitting out to the terminal. However, we don't..
If I un-comment the Thread.sleep lines inside the thread loop, the program works as expected and we see the many lines of 'True' being printed after we change the value in the App object. As an addition, any print method in place of the Thread.sleep also works, but some simple assignment code does not. I assume this is because it is pulled out as un-used code at compile time.
So, my question is really: Why do I have to use some kind of interruption to get the thread to check conditions correctly?
So, my question is really: Why do I have to use some kind of interruption to get the thread to check conditions correctly?
Well you don't have to. There are at least two ways to implement this particular example without using "interruption".
If you declare flag to be volatile, then it will work.
It will also work if you declare flag to be private, write synchronized getter and setter methods, and use those for all accesses.
public class App {
public static void main(String[] args) {
App app = new App();
}
class Test implements Runnable {
private boolean flag = false;
public synchronized boolean getFlag() {
return this.flag;
}
public synchronized void setFlag(boolean flag) {
return this.flag = flag;
}
public void run() {
while(true) {
if (this.getFlag()) { // Must use the getter here too!
System.out.println("True");
}
}
}
}
public App() {
Test t = new Test();
Thread thread = new Thread(t);
System.out.println("Starting thread");
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
t.setFlag(true);
System.out.println("New flag value: " + t.getFlag());
}
But why do you need to do this?
Because unless you use either a volatile or synchronized (and you use synchronized correctly) then one thread is not guaranteed to see memory changes made by another thread.
In your example, the child thread does not see the up-to-date value of flag. (It is not that the conditions themselves are incorrect or "don't work". They are actually getting stale inputs. This is "garbage in, garbage out".)
The Java Language Specification sets out precisely the conditions under which one thread is guaranteed to see (previous) writes made by another thread. This part of the spec is called the Java Memory Model, and it is in JLS 17.4. There is a more easy to understand explanation in Java Concurrency in Practice by Brian Goetz et al.
Note that the unexpected behavior could be due to the JIT deciding to keep the flag in a register. It could also be that the JIT compiler has decided it does not need force memory cache write-through, etcetera. (The JIT compiler doesn't want to force write-through on every memory write to every field. That would be a major performance hit on multi-core systems ... which most modern machines are.)
The Java interruption mechanism is yet another way to deal with this. You don't need any synchronization because the method calls that. In addition, interruption will work when the thread you are trying to interrupt is currently waiting or blocked on an interruptible operation; e.g. in an Object::wait call.
Because the variable is not modified in that thread, the JVM is free to effectively optimize the check away. To force an actual check, use the volatile keyword:
public volatile boolean flag = false;

How should I interrupt and dispose of a group of threads in java?

I'm writing a game engine which performs alhpa-beta search on at a game state, and I'm trying to parallelize it. What I have so far is working at first, and then it seems to slow to a halt. I suspect that this is because I'm not correctly disposing of my threads.
When playing against the computer, the game calls on the getMove() function of a MultiThreadedComputerPlayer object. Here is the code for that method:
public void getMove(){
int n = board.legalMoves.size();
threadList = new ArrayList<WeightedMultiThread>();
moveEvals = new HashMap<Tuple, Integer>();
// Whenever a thread finishes its work at a given depth, it awaits() the other threads
// When all threads are finished, the move evaluations are updated and the threads continue their work.
CyclicBarrier barrier = new CyclicBarrier(n, new Runnable(){
public void run() {
for(WeightedMultiThread t : threadList){
moveEvals.put(t.move, t.eval);
}
}
});
// Prepare and start the threads
for (Tuple move : board.legalMoves) {
MCBoard nextBoard = board.clone();
nextBoard.move(move);
threadList.add(new WeightedMultiThread(nextBoard, weights, barrier));
moveEvals.put(move, 0);
}
for (WeightedMultiThread t : threadList) {t.start();}
// Let the threads run for the maximum amount of time per move
try {
Thread.sleep(timePerMove);
} catch (InterruptedException e) {System.out.println(e);}
for (WeightedMultiThread t : threadList) {
t.stop();
}
// Play the best move
Integer best = infHolder.MIN;
Tuple nextMove = board.legalMoves.get(0);
for (Tuple m : board.legalMoves) {
if (moveEvals.get(m) > best) {
best = moveEvals.get(m);
nextMove = m;
}
}
System.out.println(nextMove + " is the choice of " + name + " given evals:");
for (WeightedMultiThread t : threadList) {
System.out.println(t);
}
board.move(nextMove);
}
And here run() method of the threads in question:
public void run() {
startTime = System.currentTimeMillis();
while(true) {
int nextEval = alphabeta(0, infHolder.MIN, infHolder.MAX);
try{barrier.await();} catch (Exception e) {}
eval = nextEval;
depth += 1;
}
}
I need to be able to interrupt all the threads when time is up-- how am I supposed to implement this? As of now I'm constantly catching (and ignoring) InterruptedExceptions.
Thread.stop was deprecated for a reason. When you interrupt a thread in the middle, the thread doesn't have the chance to properly release resources it was using, and doesn't notify other threads of its completion...something that's very important in multi-threaded apps. I'm not surprised your performance tanks; I would be willing to bet your memory usage shoots through the roof. You also don't recycle the threads, you start and stop them without creating new objects, which means whatever broken state the variables were left in is probably still plaguing them.
A better way is to set a flag that tells the thread it should return. So include in your WeightedMultiThread class a boolean named something like shouldQuit, and set it to false every time start() is called. Then, instead of while (true) do while (!shouldQuit), and instead of t.stop(), use t.shouldQuit = true. After you do that to every thread, have another loop that checks each thread for t.isAlive(), and once every thread has returned, go about your business. You should have much better results that way.
This looks like an ideal place to use an ExecutorService. You can create Callable instances that implement the parallel tasks, submit them to the ExecutorService, then use awaitTermination to enforce a timeout.
For example:
public void getMove() {
ExecutorService service = Executors.newFixedThreadPool(board.legalMoves.size());
List<Future<Something>> futures = new ArrayList<Future<Something>>(board.legalMoves.size());
for (Tuple move : board.legalMoves) {
futures.add(service.submit(new WeightedMultiThread(...)));
}
service.awaitTermination(timePerMove, TimeUnit.MILLISECONDS);
service.shutdownNow(); // Terminate all still-running jobs
for (Future<Something> future : futures) {
if (future.isDone()) {
Something something = future.get();
// Add best move logic here
}
}
...
}
Replace Something with something that encapsulates information about the move that has been evaluated. I'd suggest Something be a class that holds the Tuple and its associated score. Your WeightedMultiThread class can do something like this:
class WeightedMultiThread implements Callable<Something> {
public Something call() {
// Compute score
...
// Return an appropriate data structure
return new Something(tuple, score);
}
}
Even better would be to create the ExecutorService once and re-use it for each call to getMove. Creating threads is expensive, so best to only do it once if you can. If you take this approach then you should not call shutdownNow, but instead use the Future.cancel method to terminate jobs that have not completed in time. Make sure your WeightedMultiThread implementation checks for thread interruption and throws an InterruptedException. That's usually a good way to write a long-running task that needs to be interruptible.
EDIT:
Since you're doing a level-by-level exploration of the game space, I'd suggest that you encode that in the getMove function rather than in the Tuple evaluation code, e.g.
public Tuple getMove() {
ExecutorService service = ...
Tuple best = null;
long timeRemaining = MAX_TIME;
for (int depth = 0; depth < MAX_DEPTH && timeRemaining > 0; ++depth) {
long start = System.currentTimeMillis();
best = evaluateMoves(depth, service, timeRemaining);
long end = System.currentTimeMillis();
timeRemaining -= (end - start);
}
return best;
}
private Tuple evaluateMoves(int depth, ExecutorService service, long timeRemaining) {
List<Future<Whatever>> futures = service.submit(...); // Create all jobs at this depth
service.awaitTermination(timeRemaining, TimeUnit.MILLISECONDS);
// Find best move
...
return best;
}
That could probably be cleaner, but you get the idea.
The most sensitive way is to use interruption mechanism. Thread.interrupt() and Thread.isInterrupted() methods. This ensures your message will be delivered to a thread even if it sits inside a blocking call (remember some methods declare throwing InterruptedException?)
P.S. It would be useful to read Brian Goetz's "Java Concurrency in Practice" Chapter 7: Cancellation and Shutdown.

Have threads run indefinitely in a java application

I am trying to program a game in which I have a Table class and each person sitting at the table is a separate thread. The game involves the people passing tokens around and then stopping when the party chime sounds.
how do i program the run() method so that once I start the person threads, they do not die and are alive until the end of the game
One solution that I tried was having a while (true) {} loop in the run() method but that increases my CPU utilization to around 60-70 percent. Is there a better method?
While yes, you need a loop (while is only one way, but it is simplest) you also need to put something inside the loop that waits for things to happen and responds to them. You're aiming to have something like this pseudocode:
loop {
event = WaitForEvent();
RespondToEvent(event);
} until done;
OK, that's the view from 40,000 feet (where everything looks like ants!) but it's still the core of what you want. Oh, and you also need something to fire off the first event that starts the game, obviously.
So, the key then becomes the definition of WaitForEvent(). The classic there is to use a queue to hold the events, and to make blocking reads from the queue so that things wait until something else puts an event in the queue. This is really a Concurrency-101 data-structure, but an ArrayBlockingQueue is already defined correctly and so is what I'd use in my first implementation. You'll probably want to hide its use inside a subclass of Thread, perhaps like this:
public abstract class EventHandlingThread<Event> extends Thread {
private ArrayBlockingQueue<Event> queue = new ArrayBlockingQueue<Event>();
private boolean done;
protected abstract void respondToEvent(Event event);
public final void postEvent(Event event) throws InterruptedException {
queue.put(event);
}
protected final void done() {
done = true;
}
public final void run() {
try {
while (!done) {
respondToEvent(queue.take());
}
} catch (InterruptedException e) {
// Maybe log this, maybe not...
} catch (RuntimeException e) {
// Probably should log this!
}
}
}
Subclass that for each of your tasks and you should be able to get going nicely. The postEvent() method is called by other threads to send messages in, and you call done() on yourself when you've decided enough is enough. You should also make sure that you've always got some event that can be sent in which terminates things so that you can quit the gameā€¦
I would look into Locks and Conditions. This way you can write code that waits for a certain condition to happen. This won't take a lot of CPU power and is even much more efficient and better performing than sleeping .
To make a thread run for an infinite time:
final Object obj = new Object();
try {
Thread th = new Thread(new Runnable() {
public void run() {
synchronized(obj) {
try {
System.out.println("Waiting");
obj.wait();
System.out.println("Done waiting");
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
});
th.start();
System.out.println("Waiting to join.");
// Dont notify; but wait for joining. This will ensure that main thread is running always.
th.join();
System.out.println("End of the Program");
} catch(Exception ex) {
ex.printStackTrace();
}
You may add Thread.sleep() with appropriate time to minimize useless loop iterations.
Another solution is using synchronization. While threads are not required to do anything, they enter into a sleeping state on a monitor using the wait() method, and then when the turn comes, required thread is woken up by the notify() method.
Actor model seems suitable for this scenario. Each person sitting on the table and the table itself can be modelled as actors and the event of passing the tokens and starting and stopping of the game can be modelled as messages to be passed between the actors.
As a bonus, by modelling the scenario as actors you get rid of explicit manipulation of threads, synchronization and locking.
On JVM I will prefer using Scala for modelling actors. For Java you can use libraries like Kilim. See this post for a comparison of Actor model related libraries in Java.
One Way is to use while loop but keep a check i.e
while(true){
if(condition!=true){
Thread.sleep(time);
}else{
break;
}
}
This way if your condition says game is not over it will keep person thread at sleep and memory consumption will be very low.
You should test for a condition in the while loop:
while (!gameOver)
{
do_intersting_stuff();
}
Heavy CPU load is typical for busy wait. Is your loop actually just checking a flag over and over, like
while (!gameOver)
{
if (actionNeeded)
{
do_something();
}
}
you might change to another notification system to sleep and wake up, as this just burns CPU time for nothing.

How can I wrap a method so that I can kill its execution if it exceeds a specified timeout?

I have a method that I would like to call. However, I'm looking for a clean, simple way to kill it or force it to return if it is taking too long to execute.
I'm using Java.
to illustrate:
logger.info("sequentially executing all batches...");
for (TestExecutor executor : builder.getExecutors()) {
logger.info("executing batch...");
executor.execute();
}
I figure the TestExecutor class should implement Callable and continue in that direction.
But all i want to be able to do is stop executor.execute() if it's taking too long.
Suggestions...?
EDIT
Many of the suggestions received assume that the method being executed that takes a long time contains some kind of loop and that a variable could periodically be checked.
However, this is not the case. So something that won't necessarily be clean and that will just stop the execution whereever it is is acceptable.
You should take a look at these classes :
FutureTask, Callable, Executors
Here is an example :
public class TimeoutExample {
public static Object myMethod() {
// does your thing and taking a long time to execute
return someResult;
}
public static void main(final String[] args) {
Callable<Object> callable = new Callable<Object>() {
public Object call() throws Exception {
return myMethod();
}
};
ExecutorService executorService = Executors.newCachedThreadPool();
Future<Object> task = executorService.submit(callable);
try {
// ok, wait for 30 seconds max
Object result = task.get(30, TimeUnit.SECONDS);
System.out.println("Finished with result: " + result);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (TimeoutException e) {
System.out.println("timeout...");
} catch (InterruptedException e) {
System.out.println("interrupted");
}
}
}
Java's interruption mechanism is intended for this kind of scenario. If the method that you wish to abort is executing a loop, just have it check the thread's interrupted status on every iteration. If it's interrupted, throw an InterruptedException.
Then, when you want to abort, you just have to invoke interrupt on the appropriate thread.
Alternatively, you can use the approach Sun suggest as an alternative to the deprecated stop method. This doesn't involve throwing any exceptions, the method would just return normally.
I'm assuming the use of multiple threads in the following statements.
I've done some reading in this area and most authors say that it's a bad idea to kill another thread.
If the function that you want to kill can be designed to periodically check a variable or synchronization primitive, and then terminate cleanly if that variable or synchronization primitive is set, that would be pretty clean. Then some sort of monitor thread can sleep for a number of milliseconds and then set the variable or synchronization primitive.
Really, you can't... The only way to do it is to either use thread.stop, agree on a 'cooperative' method (e.g. occassionally check for Thread.isInterrupted or call a method which throws an InterruptedException, e.g. Thread.sleep()), or somehow invoke the method in another JVM entirely.
For certain kinds of tests, calling stop() is okay, but it will probably damage the state of your test suite, so you'll have to relaunch the JVM after each call to stop() if you want to avoid interaction effects.
For a good description of how to implement the cooperative approach, check out Sun's FAQ on the deprecated Thread methods.
For an example of this approach in real life, Eclipse RCP's Job API's 'IProgressMonitor' object allows some management service to signal sub-processes (via the 'cancel' method) that they should stop. Of course, that relies on the methods to actually check the isCancelled method regularly, which they often fail to do.
A hybrid approach might be to ask the thread nicely with interrupt, then insist a couple of seconds later with stop. Again, you shouldn't use stop in production code, but it might be fine in this case, esp. if you exit the JVM soon after.
To test this approach, I wrote a simple harness, which takes a runnable and tries to execute it. Feel free to comment/edit.
public void testStop(Runnable r) {
Thread t = new Thread(r);
t.start();
try {
t.join(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!t.isAlive()) {
System.err.println("Finished on time.");
return;
}
try {
t.interrupt();
t.join(2000);
if (!t.isAlive()) {
System.err.println("cooperative stop");
return;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.err.println("non-cooperative stop");
StackTraceElement[] trace = Thread.getAllStackTraces().get(t);
if (null != trace) {
Throwable temp = new Throwable();
temp.setStackTrace(trace);
temp.printStackTrace();
}
t.stop();
System.err.println("stopped non-cooperative thread");
}
To test it, I wrote two competing infinite loops, one cooperative, and one that never checks its thread's interrupted bit.
public void cooperative() {
try {
for (;;) {
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.err.println("cooperative() interrupted");
} finally {
System.err.println("cooperative() finally");
}
}
public void noncooperative() {
try {
for (;;) {
Thread.yield();
}
} finally {
System.err.println("noncooperative() finally");
}
}
Finally, I wrote the tests (JUnit 4) to exercise them:
#Test
public void testStopCooperative() {
testStop(new Runnable() {
#Override
public void run() {
cooperative();
}
});
}
#Test
public void testStopNoncooperative() {
testStop(new Runnable() {
#Override
public void run() {
noncooperative();
}
});
}
I had never used Thread.stop() before, so I was unaware of its operation. It works by throwing a ThreadDeath object from whereever the target thread is currently running. This extends Error. So, while it doesn't always work cleanly, it will usually leave simple programs with a fairly reasonable program state. For example, any finally blocks are called. If you wanted to be a real jerk, you could catch ThreadDeath (or Error), and keep running, anyway!
If nothing else, this really makes me wish more code followed the IProgressMonitor approach - adding another parameter to methods that might take a while, and encouraging the implementor of the method to occasionally poll the Monitor object to see if the user wants the system to give up. I'll try to follow this pattern in the future, especially methods that might be interactive. Of course, you don't necessarily know in advance which methods will be used this way, but that is what Profilers are for, I guess.
As for the 'start another JVM entirely' method, that will take more work. I don't know if anyone has written a delegating class loader, or if one is included in the JVM, but that would be required for this approach.
Nobody answered it directly, so here's the closest thing i can give you in a short amount of psuedo code:
wrap the method in a runnable/callable. The method itself is going to have to check for interrupted status if you want it to stop (for example, if this method is a loop, inside the loop check for Thread.currentThread().isInterrupted and if so, stop the loop (don't check on every iteration though, or you'll just slow stuff down.
in the wrapping method, use thread.join(timeout) to wait the time you want to let the method run. or, inside a loop there, call join repeatedly with a smaller timeout if you need to do other things while waiting. if the method doesn't finish, after joining, use the above recommendations for aborting fast/clean.
so code wise, old code:
void myMethod()
{
methodTakingAllTheTime();
}
new code:
void myMethod()
{
Thread t = new Thread(new Runnable()
{
public void run()
{
methodTakingAllTheTime(); // modify the internals of this method to check for interruption
}
});
t.join(5000); // 5 seconds
t.interrupt();
}
but again, for this to work well, you'll still have to modify methodTakingAllTheTime or that thread will just continue to run after you've called interrupt.
The correct answer is, I believe, to create a Runnable to execute the sub-program, and run this in a separate Thread. THe Runnable may be a FutureTask, which you can run with a timeout ("get" method). If it times out, you'll get a TimeoutException, in which I suggest you
call thread.interrupt() to attempt to end it in a semi-cooperative manner (many library calls seem to be sensitive to this, so it will probably work)
wait a little (Thread.sleep(300))
and then, if the thread is still active (thread.isActive()), call thread.stop(). This is a deprecated method, but apparently the only game in town short of running a separate process with all that this entails.
In my application, where I run untrusted, uncooperative code written by my beginner students, I do the above, ensuring that the killed thread never has (write) access to any objects that survive its death. This includes the object that houses the called method, which is discarded if a timeout occurs. (I tell my students to avoid timeouts, because their agent will be disqualified.) I am unsure about memory leaks...
I distinguish between long runtimes (method terminates) and hard timeouts - the hard timeouts are longer and meant to catch the case when code does not terminate at all, as opposed to being slow.
From my research, Java does not seem to have a non-deprecated provision for running non-cooperative code, which, in a way, is a gaping hole in the security model. Either I can run foreign code and control the permissions it has (SecurityManager), or I cannot run foreign code, because it might end up taking up a whole CPU with no non-deprecated means to stop it.
double x = 2.0;
while(true) {x = x*x}; // do not terminate
System.out.print(x); // prevent optimization
I can think of a not so great way to do this. If you can detect when it is taking too much time, you can have the method check for a boolean in every step. Have the program change the value of the boolean tooMuchTime to true if it is taking too much time (I can't help with this). Then use something like this:
Method(){
//task1
if (tooMuchTime == true) return;
//task2
if (tooMuchTime == true) return;
//task3
if (tooMuchTime == true) return;
//task4
if (tooMuchTime == true) return;
//task5
if (tooMuchTime == true) return;
//final task
}

Categories