We are seeing frequent timing issues in our nightly UI tests. The tests often fail because events performed by the java.awt.Robot have not completed before the test code tries to verifying the results.
We are code like using:
Point p = cb.getLocationOnScreen();
int m = 5;
if (cb.getWidth()<5||cb.getHeight()<5)
m=3;
System.out.println("Click at " + (p.x+m) + "," + (p.y+m));
robot.mouseMove(p.x + m, p.y + m);
robot.mousePress(MouseEvent.BUTTON1_MASK);
robot.mouseRelease(MouseEvent.BUTTON1_MASK);
robot.waitForIdle();
Thread.sleep(100);
// Verify results...
We keep having the bump up the Thread.sleep to ensure things complete on the event thread (things like clicking on a button or typing text) despite the java.awt.Robot.waitForIdle() call.
I found this question (Does java.awt.Robot.waitForIdle() wait for events to be dispatched?) which says to use java.awt.Toolkit.realSync(), but this is not an accessible method and with Java 9 coming, I'd rather not add any unnecessary reflection to our tests.
Are there better solutions? Or do people use realSync() or just increase the wait time until tests pass reliably?
UPDATE
I tried using sun.awt.SunToolkit.realSync(), but it is hanging in some tests and never returning. It looks like the EventThread is painting borders and such.
Looks like my only solution is to bump the sleep time up until the test can actually pass reliably. Yuck.
UPDATE 2
I figured out the first hang I had with realSync(). It was a problem in our code, where some paint code called a get method that called a set method which queued up another paint. Repeat forever.
Fixed our code and realSync() worked for a while, sort of. It still seems to return before it should. No idea why and I have no work around.
Also, I've seen realSync() hang and time out on my Linux box running under Java 1.7, but it works under Java 1.8. Very reliable tool here. /s
So, back the to original question. What is a decent way to tell when UI updates are done?
I came to the conclusion that I did need to use SunToolkit.realSync() and it seems to work correctly for Java 9 as well.
It seems, although I couldn't find any hard evidence, that realSync() waits for all graphics related threads while Robot.waitForIdle() and SwingUntilities.invokeLater() only wait for the Java EventThread to finish it's work.
If someone comes up with a better answer, I'd being will to accept that instead of my answer.
Related
I have a very dumb question.
If I use AtomicReferences compareAndSet
this way
original.set(atomic.get());
long next = some new value
atomic.compareAndSet(original.get(), next);
....more code....
is more code still updated if the comparison fails (i.e. atomic has been updated by another thread).
I'm trying to find an error in an assignment and this is the only thing I can think about and I've been trying for few hours.
P.S.
Weirdly enough, if I use synchronize on this code
it gives me the correct answer on my laptop, but not on my desktop
MangatRaiModi and SotiriosDelimanolis put me on the right path.
A simple fix:
original.set(atomic.get());
long next = some new value
while(!atomic.compareAndSet(original.get(), next))
{
do above again
}
....more code....
did it.
Still not sure how synchronized fixed this on my laptop but not on my desktop.
I'm guessing that it's slowing the threads down on the mobile Chip enough so that they can operate sequentially (Like a Print statement).
I'm probably wrong though.
I'm currently reading about game development, every time I see a game loop implemented it is always the same way.
A while(true) block, with a sleep inside for the FPS.
And I'm asking myself, why shouldn't I use a scheduledExcecutor, it seems like the obvious choice?
I mean, I'm sure I'm wrong here, it's unlikely that I'm the first one to think of this, but WHY not ?
First of all, look at some of the evolution of the traditional game loop. Your while(true) + sleep example is the simplest one.
Then people noticed that games were affected by the speed of the computer they were running on. Look up "variable time step game loop" on Google, for examples of how this is dealt with.
Now read over the docs on the ScheduledExecutorService. Neither scheduleAtFixedRate nor scheduleWithFixedDelay are quite what you'd want for a game.
Also, scrolling down in the docs, you'll notice "If any execution of the task encounters an exception, subsequent executions are suppressed." This can cause your game loop to abruptly terminate if you don't handle every possible exception.
There's nothing to stop you from extending the ScheduledExecutorService and modifying it to suit your needs, but I wouldn't recommend it as-is.
The main reason is probably simply that most of the code you are reading was coded before (or following patterns that were coded before) the concurrent package came out/was in heavy use.
A secondary might be trust. When you are coding something that critical to your app you want to be sure exactly how it behaves. The while(true) loop makes it very clear exactly what's going on... You'd have to spend some time dealing with the various executors before you became truly comfortable with one.
There should be a solution that solves your problem, I'm sure you can find something that fires regularly, and has an adjustment in case one iteration takes a little longer than expected.
You may even want to build your own executor. The pattern itself is fine, it's just finding a way to make it work for you.
I am developing a game on android, 'Space RPG' - currently only seeing this error pop up on most Galaxy S4s, and HTC Ones. This is all Java.
The game will stall, when I try to debug the process and suspend the thread in question, it won't suspend, and a spin-on-suspend error happens.
The thread dump lets me see that it was inside a certain while loop that is taking a desired 'end position' and iterating backwards at an ever increasing distance step to find a 'start position'.
This is where things get annoying. I can verify that the loop can not run indefinitely, even though the condition is while(true), it is not possible for it to run more than maybe 200 iterations before my break gets called (this assertion being backed up by the code working on every other phone I have tried).
To help ease my mind on this matter, I added a simple incremented variable inside the loop, and if it ever goes above 1000 it will log something out so I can see that it DID run too many times, just in case some variable was set badly or something.
When this counter code is present, NO crash/hang occurs. Nor do I see any logs indicating it ran over 1000 times.
If I remove this counter, the hang occurs every time after 5-10 seconds of playing [in which the while loop will have run maybe 10 times, though that varies].
My question is therefore, what the hell is going on? :P
Why would these newer phones (but seemingly none of the older phones) have a problem with a loop that is doing valid work and doesn't last long, when there is no incremented variable in there. How could the thread possibly stall in that loop, and how does having an extra counter variable fix the issue?
This work is being done on the opengl render thread, in case that is important.
I have reports of this happening on most S4s, but there is at least one S4 out there where it didn't happen. The one I am using today it IS happening. This makes me wonder if it could possibly be to do with the specific android, java, dalvik or something else on the phone but I unfortunately dont have any details from the S4 where it worked.
Any help, guidance, thoughts or further reading on stuff like this would be appreciated, thanks a lot.
float vel = 1.0f; // final velocity is 1. We are working backwards to find out what the starting velocity will need to be.
int i = 0;
double xmath = Math.sin(rot* (Math.PI/180.0f)); // component of velocity for x,y direction based on rotation
double ymath = Math.cos(rot* (Math.PI/180.0f));
while (true) {
/* with this section uncommented, the stall never happens...
++i;
if (i>1000) {
// Something went rather wrong
vel = 91.0f; // LOG WAS HERE, now has a fallback value justincase
break;
}
*/
vel *= 1.2f;
dx -= vel* xmath;
dy += vel* ymath;
if (distance < (float)Math.sqrt(dx*dx+dy*dy)) {
break;
}
}
// Give the ship a velocity that is appropriate for the distance remaining
_AI.Ship.Velocity = vel;
This is probably http://b.android.com/58726.
The bug has full details; in short: some vendors appear to use a modified version of the Dalvik VM. Changes made to the JIT compiler prevent thread suspension from occurring in certain situations.
The litmus test for this issue is to compare the standard retail device against the "pure Android" Google Play Edition of the GS4 and HTC1. If the former shows the broken behavior, but the latter works correctly, you are likely seeing a vendor-specific problem.
The workaround is to do what you've done: make the code less efficient so it doesn't fall into the "optimized" case. Ideally the app would runtime-select a different code path for devices without the issue, but I don't know of a good way to detect the problem at run time.
I debugged my java code. It didn't give any errors.But when i executed it (it isn't giving errors either, but) the code didn't successfully terminate. This is very funny. But is that even possible?
sure, when the slowdown introduced by debugger does mask some race condition, but this normally only applies to multi-threading or networking code.
Yes it is possible that code works when debugging and doesn't work when running. Two possible reasons I can think of right now are
Concurrency in case of multithreading: if your debugger stops on a breakpoint, timing between multiple threads can change which can influence the behaviour
When debugging, you can trigger certain parts of the code multiple times (more than when it has been executed without debugging), like for example via the toString method or via doing inspects or having some watch expression configured
Yes, your code can be syntactically correct (and thus might run without any errors) but may be semantically incorrect.
Assume the following:
public int add( int operand1, int operand2)
{
return operant1 - operand2;
}
This would run without errors but still be incorrect due to logic/implementation error.
So, it IS possible to get wrong results by otherwise smoothly running code.
I have a piece of code that looks like this:
Algorithm a = null;
while(a == null)
{
a = grid.getAlgorithm();
}
getAlgorithm() in my Grid class returns some subtype of Algorithm depending on what the user chooses from some options.
My problem is that even after an algorithm is selected, the loop never terminates. However, that's not the tricky bit, if I simply place a System.out.println("Got here"); after my call to getAlgorithm(), the program runs perfectly fine and the loop terminates as intended.
My question is: why does adding that magic print statement suddenly make the loop terminate?
Moreover, this issue first came up when I started using my new laptop, I doubt that's related, but I figured it would be worth mentioning.
Edit: The program in question is NOT multithreaded. The code for getAlgorithm() is:
public Algorithm getAlgorithm ()
{
return algorithm;
}
Where algorithm is initially null, but will change value upon some user input.
I believe the issue has to deal with how grid.getAlgorithm is executed. If there is very little cost associated with executing the method, then your while loop will cycle very quickly as long the method continues to return null. That is often referred to as a busy wait.
Now it sounds like your new laptop is encountering a starvation issue which didn't manifest on your old computer. It is hard to say why but if you look at the link I included above, the Wikipedia article does indicate that busy waits do have unpredictable behavior. Maybe your old computer handles user IO better than your new laptop. Regardless, on your new laptop, that loop is taking resources away from whatever is handling your user IO hence it is starving the process that is responsible for breaking the loop.
You are doing active polling. This is a bad practice. You should at least let the polling thread sleep (with Thread.sleep). Since println does some io, it probably does just that. If your app is not multithreaded it is unlikely to work at all.
If this loop is to wait for user input in a GUI then ouch. Bad, bad idea and even with Thread.sleep() added I'd never recommend it. Instead, you most likely want to register an event listener on the component in question, and only have the validation code fire off when the contents change.
It's more than likely you're program is locking up because you've reached some form of deadlock more than anything else, especially if your application is multithreaded. Rather than try to solve this issue and hack your way round it, I'd seriously consider redesigning how this part of the application works.
You should check getAlgorithm(), there must be something wrong in the method.
There are two scenarios:
Your code is really not meant to be multi-threaded. In this case you need to insert some sort of user input in the loop. Otherwise you might as well leave it as Algorithm a = grid.getAlgorithm(); and prevent the infinite loop.
Your code is multi-threaded in which case you have some sort of 'visibility' problem. Go to Atomicity, Visibility and Ordering or read Java Concurrency in Practice to learn more about visibility. Essentially it means that without some sort of synchronization between threads, the thread you are looping in may never find out that the value has changed due to optimizations the JVM may perform.
You did not mention any context around how this code is run. If it is a console based application and you started from a 'main' function, you would know if there was multi-threading. I am assuming this is not the case since you say there is no multithreading. Another option would be that this is a swing application in which case you should read Multithreaded Swing Applications. It might be a web application in which case a similar case to swing might apply.
In any case you could always debug the application to see which thread is writing to the 'algorithm' variable, then see which thread is reading from it.
I hope this is helpful. In any case, you may find more help if you give a little more context in your question. Especially for a question with such an intriguing title as 'Weird Java problem, while loop termination'.