My game is basically a player controlling a ball with an accelerometer embedded in a hardware system (such as an Android phone). The ball is used to knock other balls into a hole (the goal) in order to complete the level. There are many levels with objects interacting with the player's ball and the balls that should be knocked into the goal.
This game doesn't sounds complicated enough to require multi-threading when rendering. Arguably it might not require any threading at all.
About the game logic, the game itself is split into two groups, the Update group and the Rendering group. It's multithreaded and it's done in a simple way of abusing the nature of threads. Like many other people have said time and time again, threads are run inconsistently together, causing many race conditions and multiple complex problems if not handled correctly. By understanding the nature of how threads compete one another on the CPU cores (in this case, I have two cores), I utilize a parallel programming paradigm.
One thread is used to update logic ONLY. The other thread is used to render objects ONLY. And that's it. All variables are read-only if thread A wants to read what thread B is using, and vice versa. I have not done anything with concurrency in order to make both of these threads communicate with each other. I simply made them as separate processes with "global-ish" variables wrapped in a Java class (namespace, as you would call it).
When I test the program out, all is fine. Everything run as expected, and there's no bugs on the rendering or updates. It's a perfect combination.
Unfortunately, it sounds like you have a latent bug. Your current combination of code, hardware and JVM implementation might not manifest the bug, but a change in any of these could break your program.
The problem is simple: Java doesn't guarantee that a thread will see a "consistent" view of the state of the program modified by other threads in the absence of
synchronized (or Java classes/methods that have the same memory model semantics as synchronized (e.g. Atomic classes, volatile variables or explicit locks).
There are two particularly interesting cases of bugs caused by this.
One is that thread A does not see changes made by thread B at all - each thread might be only reading and writing to its own registers and processor caches, and in the absence of synchronization there is no reason for the JVM to explicitly let the processor know it must flush these local changes to main memory, and for the second thread to reload any changes.
The second is that thread A sees some of the actions of thread B, but in an unexpected order or even in seemingly "impossible" orders. For example, it is possible for a thread to see a partially constructed object in the following code:
private static Foo sharedFoo = null;
public static Foo getFoo()
{
if(sharedFoo == null) {
Foo foo = new Foo(42);
sharedFoo = foo;
}
return sharedFoo;
}
Even though Foo's constructor sets some field to the passed value, if two threads race on this method then it is possible for the following interaction to take place:
Thread A - Calls getFoo().getValue()
Thread A - Enter method getFoo()
Thread A - sharedFoo == null
Thread A - Allocate memory for "foo" // Note: for this example we presume the JVM zeros the allocated memory.
Thread A - set sharedFoo to reference this memory
>>> Context switch <<<
Thread B - Calls getFoo().getValue()
Thread B - Enter method getFoo()
Thread B - sharedFoo != null
Thread B - return sharedFoo
Thread B - getValue() returns 0 // !!!
>>> Context switch <<<
Thread A - Calls constructor for "foo"
Thread A - return sharedFoo
Thread A - getValue() returns 42
It might seem odd that the constructor of "foo" is run after the reference "sharedFoo" has been set, but this is a perfectly valid optimisation for the JVM/hardware to perform in the absence of synchronisation. If the constructor was even more complicated, you could end up with one thread seeing a class instance with the invariants broken!
But, there are times when I felt it is running slow after a long period of processing the threads, updates, and rendering.
If your game is running slow I am positive there are much better ways to get better performance. In any case, your first step should be to profile the application and determine the source of the slowness.
Adding threads can slow an application down - unless done with care.
If "synchronized" is the answer to all of my questions, then it's either me not looking at it correctly or it's something I find it hard to grasp, yet can't find out why. But I did some more research before posting this.
The function pipe I drew in the diagram may well be a Java synchronized method. In order to let two threads go in one by one and on a tight, repeating loop, I have to understand the concept of notify(), notifyAll() and wait() and how it works in such a loop... This is the part where I'm probably stuck in, and had me lost my focus, I believe.
One could use
synchronized to get the kind of pattern you described above. However, the code would actually run slower than if you had a single thread alternating between the two actions.