The Problem
I am currently halfway through building a Game of Life simulator in Java (in Eclipse), using the Swing GUI, as part of a project for college. This is going along marvellously, apart from one small flaw -
It works on my netbook, but not on any other PC I've tried. This is under Ubuntu.
Some structural outline - I have a Model, a View and a Controller. I haven't defined the Model properly yet, but I've done the View (the GUI part) and started the Controller. The Controller is run by the Main method, and the Controller then creates the View class in a separate thread and enters a while loop.
The View implements a queue of 'orders' that it has received from user input, mouse-clicks and what not. The Controller picks these orders out of the queue on an iteration of the while loop, and executes them as necessary.
However, while the code works fine on my netbook (latest version, Java 1.6.0_20), it does not work on my PC (lat开发者_开发知识库est version again, Java 1.6.0_20) or on the college PCs (karmic, some previous version of Java). It simply stops once it hits the 'getNextCommand' method. No errors, it just refuses to print/comply
The source files are located here - http://www.mediafire.com/?dfwtdkj1tdxd5xl The files of interest are Controller and View.
Example
In View, I have this function:
public Command getNextCommand() {
System.out.println(commands.getFirst().id);
return commands.pop();
}
Pretty self-explanatory, when Controller calls for getNextCommand(), it prints what command that was.
Here is the while loop in Controller:
while(!stop) {
if (gui.hasCommand()){
order = gui.getNextCommand();
//System.out.println("Something");
//if(order.id.equals("stop")) { stop = true; }
}
}
This works fine. It prints in getNextCommand as you'd expect.
Uncomment either of the two statements though, and it suddenly stops working. No more printing for you!
Why would this happen? Why would this work on my netbook, but not my PC? :C
Further notes
In addition, if I run the .class files that Eclipse makes, it prints (assuming those two lines are commented out). If I just compile them myself using javac, nothing prints.
Any insight would be appreciated!
Thanks,
Luke.
Edit
The same problem occurs if instead of returning a Command (a simple container class with an id (String), x,y (int) and value (int)) when I call getNextCommand I return an Integer. Or anything else.
Uhm, thats a classic case of a multi-threading problem, as you call view and controller from different threads. Assuming your commands container is not synchronized.
What can happpen is that an update to commands was done by one thread, however other thread didn't notice it, as the update wasn't inside synchronized block. Think of it as of two threads working on different CPU caches - when one thread writes, the other doesn't see it unless it causes cache to be flushed into main memory - and this only happens when synchronized is called.
More here: http://gee.cs.oswego.edu/dl/cpj/jmm.html
Fast solution: use java.util.vector instead of LinkedList
We need more information. What type is commands
?
Either way, a better solution than a busy wait (spinning in a while loop) is to have some sort of wait/notify mechanism. The obvious candidate for your problem seems to be a BlockingQueue
(like ArrayBlockingQueue
or LinkedBlockingQueue
). The retrieval methods of this type block until there is data (a command) available, instead of requiring you to constantly poll until there is a command available.
E.g.
BlockingQueue<Command> commands = new LinkedBlockingQueue<Command>();
//...
//wait for the next element and then get it
while(!stop) {
Command nextCommand = commands.take();
//do something with nextCommand
}
References
- LinkedBlockingQueue
More then likely there is an error that you are not catching or not handling correctly. Double check that you are not throwing out Exceptions.
Also you try cutting out pieces of the program that you think are unrelated and make sure it keeps failing. This will help you identify to true root cause.
精彩评论