So I'm doing a little experiment on exactly how far recursion can go in the Java language since I'm taking a class on concurrency and learning about Java's threading mechanisms. Right now I'm running a Intel i5 Quad-core with 2.8 GHz and 4GB of RAM. I'm running on Windows 7 with x64 and in Eclipse with the standard JRE? Not sure about that last part I just downloaded something from Sun's website.
Anyway,
public class StacksizeTest implements Runnable {
int depth = 0;
public void run()
{
try
{
doOverflow();
}
catch (StackOverflowError e)
{
System.out.print("Overflow ocurred at depth " + depth + ".\n");
}
}
void doOverflow()
{
depth += 1;
doOverflow();
}
public static void main(String argv[])
{
Thread mt = new Thread(new StacksizeTest());
mt.start();
mt.run();
}
}
I'm also running with the default call stack size, which im pretty sure is 512Mb according to the settings file.
So when I run the program and start a new thread I keep getting variable depths, as well as the print statement printing twice. The print statement makes sense I think because it should be running mt on a new thread. What I'm confused about is if I exclude .start() and just call .run() the "depth" is always the same (about 11,500 or so), but when I use .start() I'm getting variable depths. a couple have been 22789, 22330, and 22381. I'm having difficulty understanding why this is. Could someone possibly shed some light on this issue?
Thanks,
Matt
The call to .start() will start a new thread with run(), then you're calling run() again on the main thread. So you've got two stack depth threads running at the same time. Since you've also got a shared variable counting the depth that's not protected by a synchronized mutex, you've got a classic variable contention problem.
In order not to confuse the issue with variable contention, I would limit yourself to one running instance of the stack depth checker.
When you call start() you're firing off the method asynchronously, so you're running it twice because start() eventually makes a call to run(), and in addition you're calling run() yourself, so you've got two threads incrementing your depth counter. Eliminate the start(), and you get your smaller count because you're only running a single thread.
EDIT: I just saw Greg's answer. I like his more.
Related
I am trying to write a genetic program to play through a game, but I am running into a bit of a snag. When I call this code:
public double playMap (GameBoard gb, Player p) {
gb.playerController = p;
Game g = new Game(gb);
int initHP = 0;
for (Unit u : gb.enemy.units) {
initHP += u.maxHP;
}
g.playGame(false);
int finalHP = 0;
for (Unit u : gb.enemy.units) {
finalHP += u.currHP;
}
System.out.println(" " + initHP);
System.out.println(" " + finalHP);
System.out.println(" " + (finalHP - initHP));
if (initHP == finalHP) {
return -10;
}
return initHP - finalHP;
}
the g.playGame() line does not have time to finish, and I am getting incorrect results from the function. I can wait out unit the game is over with a
while (!g.isDone) {
System.out.println(g.isDone);
}
but not with the same while loop without a print statement. I know there has to be a more elegant solution, and I cant seem to implement the methods I have seen. Also if anyone knows why I need the print statement in the while loop to get it to wait that would be great too.
Thanks in advance.
ADDED playGame:
public void playGame(boolean visual) {
Global.visual = visual;
if (Global.visual) {
JFrame application = new JFrame();
application.setBackground(Color.DARK_GRAY);
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.add(this);
application.setSize(500, 400); // window is 500 pixels wide, 400 high
application.setVisible(true);
}
PlayerInput pi = new PlayerInput();
this.addKeyListener(pi);
final Timer timer = new Timer(10/60, null);
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pi.addPressed();
if (update(pi)) {
// application.setVisible(false);
// application.dispose();
System.out.println(gb.toString());
isDone = true;
timer.stop();
}
pi.reset();
}
};
timer.addActionListener(listener);
timer.start();
while (!isDone) {
System.out.println(isDone);
}
}
First of all, this is a really bad way of doing this. This approach is called "busy waiting" and it is very inefficient.
The problem is most likely that reads and writes to g.isDone are not properly synchronized. As a consequence, there are no guarantees that the "waiting" thread will ever see the update to g.isDone that sets it to true.
There are various ways to ensure that the update is seen. The simplest one is to declare isDone as volatile. Another one is to do the reads and writes within a primitive lock.
The reason that the println() call "fixes" things is that println is doing some synchronization behind the scenes, and this is leading to serendipitous cache flushing (or something) that makes your update visible. (In other words: you got lucky, but exactly how you got lucky is hard to tie down.)
A better solution is to use another mechanism for coordinating the two threads.
You could use Thread.join() so that one thread waits for the other one to terminate (completely!).
You could use a Latch or Semaphore or similar to implement the waiting.
You could use an Executor that delivers a Future and then call Future.get() to wait for that to deliver its result.
You could even use Object.wait and Object.notify ... though that is low-level and easy to get wrong.
Without seeing the full context, it is hard to judge which approach would be most appropriate. But they would all be better than busy-waiting.
Another answer says this:
If you remove the System.out.println() call from your loop, I believe that the compiler simply doesn't include the loop in the Java bytecode, believing it to be superfluous.
As I explained above, the real problem is inadequate synchronization. To be technical, there needs to be a happens-before relationship between the write of isDone in one thread and the read of isDone in the other one. Various things will give that ... but without that, the compiler is entitled to assume that:
the writing thread does not need to flush the write to memory
the reading thread does not need to check that the memory has changed.
For example, without the happens-before, the compiler would be permitted to optimize
while (!g.isDone) {
// do nothing
}
to
if (!g.isDone) {
// do nothing
}
We don't know if this actually happens, or whether the actual cause of "non-visibility" of the update to isDone is something else. (Indeed, it could be JVM version / platform specific. To be sure, you would need to get the JIT compiler to dump the native code for the methods, and analyze the code very carefully.)
Apparently you are running your game in a separate thread. Assuming that thread is called foo, calling foo.join() will block the calling thread until foo finishes executing. You can simply replace your entire loop with foo.join().
If you remove the System.out.println() call from your loop, I believe that the compiler simply doesn't include the loop in the Java bytecode, believing it to be superfluous.
In python using two Threads for a simple counter program (as demonstrated below) is slower than the program with a single thread. The reason given to this is the mechanism behind Global Interpreter lock.
I tested the same in java to see the performance. Here again, I see that a single Thread out-performs two-threaded one with a significant time scale. why is it so?
Here is the code:
public class ThreadTiming {
static void threadMessage(String message) {
String threadName =
Thread.currentThread().getName();
System.out.format("%s: %s%n",
threadName,
message);
}
private static class Counter implements Runnable {
private int count=500000000;
#Override
public void run() {
while(count>0) {
count--;
}
threadMessage("done processing");
}
}
public static void main(String[] args) throws InterruptedException{
Thread t1 = new Thread(new Counter());
Thread t2 = new Thread(new Counter());
long startTime=System.currentTimeMillis();
t1.start();
t2.start();
t1.join();
t2.join();
long endTime=System.currentTimeMillis();
System.out.println("Time taken by two threads "+ (endTime-startTime)/1000.0);
startTime=System.currentTimeMillis();
Calculate(2*500000000);
endTime=System.currentTimeMillis();
System.out.println("Time taken by single thread "+ (endTime-startTime)/1000.0);
}
public static void Calculate(int x){
while (x>0){
x--;
}
threadMessage("Done processing");
}
}
Output:
Thread-1: done processing
Thread-2: done processing
Time taken by two threads 0.052
main: Done processing
Time taken by single thread 0.0010
Very simple. The single threaded version uses a local variable which hotspot has no problems to reason that it never leaves the scope, hence the whole function is reduced to a nop.
On the other hand proving that the instance variable never leaves scope (hello reflection!) Is much harder and obviously hotspot cannot it here hence the loop isn't removed.
On a general note benchmarking is hard (i count at least three other mistakes that could lead to "wrong" results) and requires tons of knowledge.You are better off using jmh (java measuring harness) which takes care of most things.
The basic answer is you have code the optimiser can eliminate and you are timing how long it takes to detect this. You are also adding the time it takes to start and stop two threads which could be more than half this time.
The second test doesn't start a new thread, it uses the current one so you just need to wait for it to detect the loop doesn't do anything.
For example you have timed that a single thread can do 1 billion loops in 1 ms. If you have a 3.33 GHz processor, this would have to do 300 iterations in a single clock cycle. If this sounds too good to be true, that is because it is. ;)
#Voo seems to be generally right, as you can see by moving ThreadTiming.Counter.count to be a local variable of ThreadTiming.Counter.run(). That eliminates any possibility of non-local references, and the resulting program exhibits much less single-thread vs. dual-thread performance difference.
HOWEVER, that doesn't eliminate all the difference. The timing reported for the dual-thread case is still worse by about a factor of 9 for me. But if I then swap so that the single-threaded case is measured first, the two-thread case wins by about a factor of 2.
But that, too, is illusory, because the two tests are running different -- albeit similar -- code. The single-thread case can easily be made to run exactly the same code as the dual thread case:
Counter c = new Counter();
c.run();
c.run();
(Using the version where count is local to run().) If that approach is used then I observe no difference in performance (at the resolution of the measurement) between single- and dual-threaded, regardless of which case is tested first.
As #Voo said, benchmarking is hard.
It just looks like it's from loading each thread and its context into the CPU. It's thrashing. There's probably a more detailed answer waiting to strike, but let's start by posting the basics...
When running two threads, your timer is including the time taken to launch the two threads. Creating and starting threads has some overhead, and in this case, the overhead is longer than the time to actually carry out the process.
I am learning the usage of volatile in Java. Here is a sample code I read from many articles:
static volatile boolean shutdownRequested = false;
...
public void shutdown() { shutdownRequested = true; }
public void doWork() {
while (!shutdownRequested) {
// do stuff
}
}
I try this on my machine with and without "volatile", but they show no difference: they can both shutdown.
So what's wrong? Is there anything wrong with my code, or does it depend on the version of the Java compiler?
Addition: in many articles, they say this program without "volatile" will not successfully shutdown because this loop while (!shutdownRequested) will be optimized to while(true) by Java compiler if the value of the variable shutdownRequested is not changed inside the loop. But the result of my experiment does not stand for that.
I assume you mean you have a setup something like this:
final Worker theWorker = new Worker(); // the object you show code for
new Thread(new Runnable() {
public void run() {
theWorker.doWork();
}
}.start();
try {
Thread.sleep(1000L);
} catch(InterruptedException ie) {}
theWorker.shutdown();
And what you found is that the shutdown works even without volatile.
It's typically the case that this is true: non-volatile writes may be seen eventually. The important thing is that there is not a guarantee this needs to be the case and you can't rely on it. In practical use you may also find there is a small but noticeable delay without volatile.
Volatile provides a guarantee that writes are seen immediately.
Here's some code that might reproduce the HotSpot optimization we discussed in the comments:
public class HotSpotTest {
static long count;
static boolean shouldContinue = true;
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
public void run() {
while(shouldContinue) {
count++;
}
}
});
t.start();
do {
try {
Thread.sleep(1000L);
} catch(InterruptedException ie) {}
} while(count < 999999L);
shouldContinue = false;
System.out.println(
"stopping at " + count + " iterations"
);
try {
t.join();
} catch(InterruptedException ie) {}
}
}
Here's a quick review if you don't know what HotSpot is: HotSpot is the Java just-in-time compiler. After some fragment of code has run a certain number of times (from memory, 1000 for desktop JVM, 3000 for server JVM), HotSpot takes the Java bytecode, optimizes it, and compiles it to native assembly. HotSpot is one of the reasons Java is so lightning fast. In my experience, code recompiled by HotSpot can be easily 10x faster. HotSpot is also much more aggressive about optimization than a regular Java compiler (like javac or others made by IDE vendors).
So what I found is the join just hangs forever if you let the loop run long enough first. Note that count is not volatile by design. Making count volatile seems to foil the optimization.
From the perspective of the Java memory model it makes sense that as long as there is absolutely no memory synchronization HotSpot is allowed to do this. HotSpot knows there's no reason the update needs to be seen so it doesn't bother checking.
I didn't print the HotSpot assembly since that requires some JDK software I don't have installed but I'm sure if you did, you'd find the same thing the link you provided recalls. HotSpot does indeed seem to optimize while(shouldContinue) to while(true). Running the program with the -Xint option to turn HotSpot off results in the update being seen as well which also points to HotSpot as the culprit.
So, again, it just goes to show you can't rely on a non-volatile read.
Volatile is for threading. It basically tells the threads the variable can change anytime, so anytime it wants the variable it can't rely on a cached copy it must re read it and the update it after changing it
Volatile in many senses is due to the local caching that a processor can do on a per-thread basis.
for example, lest say we have a processor with 4 threads running your java program (albeit a massively simplified example since a processor would do WAY more than just this). Lets also assume that each of those 4 main threads have access to a local cache (not to be confused with a main processor cache). So, if you just made that variable static, and all 4 threads were reading from that variable, they could all potentially put that variable in their local cache. Alright, great, access time is improved, and everything is faster. So, at the moment we have the following situation:
Thread 1: has a local copy of the variable
Thread 2: has a local copy of the variable
Thread 3: '' '' '' '' '' '' ''
Thread 4: '' '' '' '' '' '' ''
Alright, now, lets say that Thread 1 goes in and changes the ACTUAL variable, not just the copy. Thread 1 knows about the change immediately, but threads 2-4 could still be working on the value of the old, cached version of the variable since they haven't checked for any updates yet.
Now, to fix this type of situation, you can attach the 'volatile' keyword to the variable, which essentially tells it to broadcast its new value to all of the threads in the program IMMEDIATELY so that any operations on all of the threads will have the exact same value. Of course, this does incur some overhead, so something that is volatile will be a touch slower if it is modified often. Since your program is not multi-threaded (that I can tell) you'll see little to no difference using volatile or not. It's simply a trivial (and pointless) extra 'command' for the variable in single-threaded environments.
Sorry, for probably a dumb question, I'm new to Java.
Is there a way to make an endless recursion in Java, somithing like:
public void sillyMethod()
{
System.out.println(i);
i++;
sillyMethod();
}
it throws StackOverflowError, but I really want to run it endless. Is there any way to make it?
Thanks!
Yes and no, (but mostly no! :)
No, it's not possible (the most sensible answer): For every call, there will be an activation record pushed onto the JVM call stack. This takes a non-zero amount of memory, thus you will at some point run out of memory, at which point a StackOverflowException will be thrown.
Yes, it is possible (the super-theoretical answer): There is nothing in the Java Language Specification that explicitly says that you should eventually run into a StackOverflowException. This means that if you find a cleaver enough compiler, it may be intelligent enough to compile this into a loop.
A related question would be, "Does the JVM support tail-call optimization." The answer to this question is, "no, not at moment, but it's not ruled out for future versions".
As others above have said, infinite recursion will eventually lead to a stack overflow, at least as far as the JVM implementation is concerned.
You could do something like this, which is similar, but avoids the stack expansion by spawning a new thread right before the old one dies.
public class SillyClass implements Runnable {
private final int count;
public SillyClass(int cnt) {
this.count = cnt;
}
public static void main(String[] args) {
Thread t = new Thread(new SillyClass(0));
t.start();
}
#Override
public void run() {
System.out.println(count);
Thread t = new Thread(new SillyClass(count + 1));
t.start();
}
}
Not recursively, no. It does imply creating an ever-increasing call stack, and eventually you will run out of memory to contain it.
With Java, you cannot do this. However, tail call optimization in languages (esp. functional ones such as Ocaml), you can do this since it internally turns it into a loop.
I'm attempting to write a junit test to guard against a piece of code getting stuck in a endless iteration which will eventually cause a StackOverflow.
so i'm looking for a way to decrease the stack size at runtime so the Junittest will fail faster.
setting the max stack as a jvm argument is not possible because the test is part of a much larger test suite.
You could run a recursive method which will run itself a given number of times and then execute a given action. Sounds pretty flaky though :(
Something like:
public void eatStackThenExecute(int depth, Runnable action)
{
// Maybe put some locals here (and use them) to eat more stack per iteration?
if (depth == 0)
{
action();
}
else
{
eatStackThenExecute(depth - 1, action);
}
}
EDIT: It's possible that smart JVMs will optimise the tail call here, so it may be that we'd need to do "something" after the recursive call to stop that from happening...
Ick 'n stuff :(
It's not possible to set the stack size at runtime, but perhaps you can:
invoke that piece of code inside a different thread - retaining the reference to it;
periodically poll thread.getStackTrace() and fail if its size is larger than x;
cancel the check if execution terminates correctly.
not-compiled proof of concept code ( does not properly check all edge conditions ):
AtomicBoolean success = new AtomicBoolean(false);
Thread t= new Thread(new Runnable() {
public void run() {
codeToTest();
success.set(true);
}
});
t.start();
while ( t.isAlive() ) {
if ( t.getStackTrace().length > 50 )
fail("Stack trace too large");
Thread.sleep(50);
}
assertTrue(sucess.get());
You can only set parameters like this at startup, however you can start another process from Java. So you could make your unit tests start a second process with a smaller stack size to perform your test.
This gets a bit... well, interesting... but it might be worth it.
Take your .class file and decompile it with jasper.
Edit the resulting JVM assembly-esque code and add or alter the ".limit stack x" argument for the routine you want to test in this manner.
Recompile with Jasmin.
Run it and test.