Is an empty while loop considered bad practice? - java

I am to download data from the server, with a maximum of 3 attempts if the download fails.
public class DownloadFile {
private boolean isSuccessful;
public DownloadFile() {
int attempt = 0;
while(!isSuccessful && (attempt++ < 3)) {
DownloadFileThread.start();
while (DownloadFileThread.isAlive());
}
}
private Thread DownloadFileThread = new Thread() {
public void run() {
try {
// download file from server
isSuccessful = true;
} catch (Exception e) {
isSuccessful = false;
}
}
}
}
As you can see in the above example, I have an empty while loop in (what would be) line 10 to force guarantee isSuccessful is assignment a value based on the outcome of the DownloadFileThread before checking the condition in the while loop again.
Is it considered bad practice to do such a thing? Is there better approach or a correct way to do this?
While the above code does produce a valid result, I am not exactly proud of the code I have written...

Yes, in this case it is a bad practice, because Java offers better mechanisms to wait for completion of a thread: Thread.join(), or consider using more modern features like CompletableFuture or an ExecutorService that allows you to wait for a task to complete.
Using an empty loop to wait will consume a lot of CPU power unnecessarily, which might mean other tasks on your system will perform slower than they could otherwise.

Not necessarily, but in this case this is a busy wait which is bad practice especially in multi-threaded programs. It keeps the CPU busy and in your case interferes with DownloadFileThread.

In your case the while loop will execute permanently stealing process time from other things, maybe also from your download thread.
If you simply want to wait until your download is done, why don´t you use Thread.join() ?
It´s blocking, meaning that you won´t be able to execute anything in your main-thread until the DownloadThread is done but your while loop does this as well in this case and use more system resources on top.

Related

Is this a safe way to synchronize a block of code?

In our application, there's a section of code that runs continuously reading and adjusting files. Just to give you a sense of what's going on:
public void run() {
try {
while(true) { //Yeah, I know...
Path currentFileName = getNextFile();
String string = readFile(currentFileName);
Files.deleteFile(currentFileName);
string = string.replaceAll("Hello", "Blarg");
writeFile(currentFileName);
}
} catch (Exception e) {
System.err.println("It's all ogre now.");
e.printStackTrace(System.err);
}
}
Elsewhere in our code is a method that might-but-usually-doesn't run on the same thread as the above code, that we use to exit the application.
private void shutdown() {
if(fileReader != null)
fileReader = null;
System.exit(0); //Don't blame me, I didn't write this code
}
As might be obvious, there's a potential Race Condition in this code, whereby if shutdown() is called between retrieving the file and then writing it back out, it'll potentially cause the file to be completely lost. This is, obviously, undesirable behavior.
There's a thousand issues with this code (outside the scope of just what I've shown here), but the main issue I need to resolve is the bad behavior where processing a file can be cut off halfway through with no recourse. My proposed solution involves simply wrapping the while loop in a synchronized block and putting a block around the System.exit call in shutdown.
So my changed code would look like this:
private Object monitor = new Object();
public void run() {
try {
while(true) {
synchronized(monitor) {
Path currentFileName = getNextFile();
String string = readFile(currentFileName);
Files.deleteFile(currentFileName);
string = string.replaceAll("Hello", "Blarg");
writeFile(currentFileName);
}
}
} catch (Exception e) {
System.err.println("It's all ogre now.");
e.printStackTrace(System.err);
}
}
private void shutdown() {
synchronized(monitor) {
if(fileReader != null)
fileReader = null;
System.exit(0);
}
}
The main thing I'm worried about is the System.exit(0); call, where I'm not certain about the total behavior behind the scenes of the call. Is there a risk that a side-effect of System.exit will be to release the lock on monitor, and thus risk the contents of the loop in run being executed partially before System.exit has caused the JVM to halt? Or will this code guarantee that the execution will never attempt a shutdown part-way through the handling of an individual file?
Note: before some armchair programmers step in with alternatives, I'd like to point out that what I've put here is a truncated version of about 4000 lines of code all stashed in a single class. Yes, it is awful. Yes, it makes me regret my chosen profession. I am not here looking for alternate solutions to this problem, I am only trying to determine if this specific solution will work, or if there's some critical flaw that would preclude it from ever working as I expect.
Or will this code guarantee that the execution will never attempt a shutdown part-way through the handling of an individual file?
This code guarantees that a shutdown initiated here will not occur part-way through handling of an individual file. Perhaps obviously, somewhere else in your code could invoke System.exit, and you have no protection from that.
You might want to consider preventing System.exit from being invoked, and then cause your code to shut down gracefully (i.e. by normal completion of the main method).
In case you really have multiple threads calling the different methods, using synchronized like this is actually a clever idea, as it takes care of that "multiple threads" thing.
You could consider reducing the scope of the first block:
Path currentFileName = getNextFile();
String string = readFile(currentFileName);
synchronized(monitor) {
reading the file alone shouldn't be a problem. (of course, unless your code here has to guarantee that a Path returned by getNextFile() gets fully processed).
If the code is executing in the synchronized block and the blocks synchronize on the same object, and the methods invoked in the synchronized block in the while loop operate entirely on the same thread as their caller, then there is no risk of the file-related processes being interrupted by that invocation of System.exit.
This said, it does look like a debatable patch only slightly improving debatable code.
There may also be a more concrete risk of starvation, as the while loop as displayed just seems to spam those file operations as fast as possible, hence the attempt to acquire the lock when exiting may not succeed.
A general direction to explore would be to transform the infinite while loop into a ScheduledExecutorService + Runnable, executing every x amount of time with its own monitor to prevent overlapping operations on the same file(s), and gracefully terminating it when the shutdown method is invoked.
You could use a shutdown hook. From the javadocs:
A shutdown hook is simply an initialized but unstarted thread. When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently.
https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#addShutdownHook(java.lang.Thread)
From this, you could provide a shutdown hook from your file class as follows:
public Thread getShutdownHook() {
return new Thread(() -> {
synchronized (monitor) {
// gracefully handle the file object
}
});
}
This will be called when Runtime.getRuntime().exit() is called (which is called by System.exit()). Since it is also synchronized on the monitor object, if the file is in use by the other thread, the shutdown hook will block until it is free.
Even if you cope with concurrent System.exit(), other reasons remain which can lead to sudden break of execution, like power outage or hardware error.
So you better do not remove the file before the new version is written. Do something like:
Path currentFileName = getNextFile();
Path tmpFileName = currentFileName+suffix();
String string = readFile(currentFileName);
string = string.replaceAll("Hello", "Blarg");
writeFile(tmpFileName);
Files.move(tmpFileName, currentFileName);

Wait for method to Finish, and weird interaction with System.println

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.

Why won't this 'if' statement run in a while loop without something else also happening in the while loop?

I'm having a problem where an if statement is only running if there is something else happening before it in the while loop.
Here is the code I want to use:
public void load() throws IOException, InterruptedException {
while (true) {
if (findGame == true) {
System.out.println(findGame);
}
}
}
That is simplified but it shows my problem. Basically, when findGame == true, the if statement does not run. The reason I don't think the if statement is running is because the variable is not being printed out to the console.
I did some tests and found that the if statement ran with the following code:
public void load() throws IOException, InterruptedException {
while (true) {
System.out.println("foo"); // New code added
if (findGame == true) {
System.out.println(findGame);
}
}
}
My question is why does it work with the above code but not the first one? The only difference between the two is that the one that works has something else added to the while loop.
If it makes a difference, the code I've shown above is running in a separate thread.
If it makes a difference, the code I've shown above is running in a separate thread.
And that's the problem. You're relying on a value set by one thread to be visible in another - and there's no such guarantee without memory barriers being involved. In your second code, the call to println is almost certainly responsible for creating the memory barriers required for the reading thread to "see" the value written by the writing thread. Memory models are hard, unfortunately :(
If you use AtomicBoolean instead of just a boolean field, you may well find the first code works instead - but even so, a tight loop is generally a bad idea. It would be better to use a semaphore or some similar kind of signalling, so the "reading" thread could just wait (idly) until there's a change. Look into java.util.concurrent for classes such as Semaphore and CountDownLatch. (You can do it with just wait and notify, but it'll be simpler if you use higher-level abstractions.)

Sparing the CPU when wait() is not available

My component integrates to a third-party component. I have to override the onTick() method which is called by a high-priority Thread of the third-party component. Sample code:
#Override
public void onTick() {
// do many useful operations
}
In certain scenarios, this onTick() method should not perform those "many useful operations", because their results are discarded. In fact, the functionality of onTick() is not needed at all in that case, but the third-party component does not offer any "pause" or "sleep" functionality. It calls onTick() all the time. This means that CPU time is used up unnecessarily in these special periods.
The most straightforward solution would be to send a signal to onTick() and make its thread sleep via an Object.wait() in a proper synchronized block. However, the documentation of the third-party component states that its Thread should not be sent to waiting state arbitrarily.
Is there any solution to save CPU resources in this case? That is, to let others use the CPU? I created the following solution, but I'm not sure it allows to save any CPU. (Nonetheless, at least, it should save other resources used by the "useful operations" section of onTick()).
#Override
public void onTick() {
// mJustUnpaused is volatile. Race condition, but probably harmless (?)
if (mJustUnpaused) {
mJustUnpaused = false;
// THREAD_PRIORITY_DISPLAY is the original
// priority used by the 3rd party Thread
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
}
if (!mRunningAllowed) {
return;
}
if (mPauseRequested) { // mPauseRequested is declared as volatile
synchronized (mPauseLock) {
if (mRunningAllowed && mPauseRequested) {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mRunningAllowed = false;
mPauseLock.notify();
}
}
return;
}
// do many useful operations
}
The methods for pausing/unpausing (the first one is blocking, the second isn't):
public void pauseWork() {
synchronized (mPauseLock) {
if (mRunningAllowed && !mPauseRequested) {
mPauseRequested = true;
while (mRunningAllowed) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {}
}
} else {
Log.d("RPT", "Already paused or pausing");
}
}
}
public void unpauseWork() {
synchronized (mPauseLock) {
if (!mRunningAllowed) {
mRunningAllowed = true;
mPauseRequested = false;
mJustUnpaused = true;
} else {
Log.d("RPT", "No need to unpause");
}
}
}
Three questions:
Is there a better way to save some CPU time?
Regardless of everything else, is my above code correct (in terms of synchronization and other programming aspects)?
Slightly off-topic, but I don't think it deserves a dedicated question: does changing a Thread's priority have any significant overhead? Are there any general guidelines when such an act can be done? (e.g. how often can it be done, etc.)
Is there a better way to save some CPU time?
I wouldn't even bother with what's there. I agree with Chris Stratton: just avoid doing the actual work, and delete the rest of the other code shown above. Then, use Traceview to see whether or not the overhead of your do-nothing onTick() calls is noticeable. Most likely, it will not be.
But I want to change the thread priority as well
That's not a good idea, as it is not your thread, if I understand the scenario properly. Moreover, I believe that you are going to be called ~300 times regardless, as if the library is coded to call you ~30 times a second, it is likely using a Timer or something else that should be relatively immune to thread priority.
Regardless of everything else, is my above code correct (in terms of synchronization and other programming aspects)?
Personally, I'd use stuff from java.util.concurrent and java.util.concurrent.atomic, rather than low-level wait()/notify()/volatile. Doug Lea is smarter than I am. :-)

How do determine if an object is locked (synchronized) so not to block in Java?

I have a process A that contains a table in memory with a set of records (recordA, recordB, etc...)
Now, this process can launch many threads that affect the records, and sometimes we can have 2 threads trying to access the same record - this situation must be denied. Specifically if a record is LOCKED by one thread I want the other thread to abort (I do not want to BLOCK or WAIT).
Currently I do something like this:
synchronized(record)
{
performOperation(record);
}
But this is causing me problems ... because while Process1 is performing the operation, if Process2 comes in it blocks/waits on the synchronized statement and when Process1 is finished it performs the operation. Instead I want something like this:
if (record is locked)
return;
synchronized(record)
{
performOperation(record);
}
Any clues on how this can be accomplished?
Any help would be much appreciated.
Thanks,
One thing to note is that the instant you receive such information, it's stale. In other words, you could be told that no-one has the lock, but then when you try to acquire it, you block because another thread took out the lock between the check and you trying to acquire it.
Brian is right to point at Lock, but I think what you really want is its tryLock method:
Lock lock = new ReentrantLock();
......
if (lock.tryLock())
{
// Got the lock
try
{
// Process record
}
finally
{
// Make sure to unlock so that we don't cause a deadlock
lock.unlock();
}
}
else
{
// Someone else had the lock, abort
}
You can also call tryLock with an amount of time to wait - so you could try to acquire it for a tenth of a second, then abort if you can't get it (for example).
(I think it's a pity that the Java API doesn't - as far as I'm aware - provide the same functionality for the "built-in" locking, as the Monitor class does in .NET. Then again, there are plenty of other things I dislike in both platforms when it comes to threading - every object potentially having a monitor, for example!)
Take a look at the Lock objects introduced in the Java 5 concurrency packages.
e.g.
Lock lock = new ReentrantLock()
if (lock.tryLock()) {
try {
// do stuff using the lock...
}
finally {
lock.unlock();
}
}
...
The ReentrantLock object is essentially doing the same thing as the traditional synchronized mechanism, but with more functionality.
EDIT: As Jon has noted, the isLocked() method tells you at that instant, and thereafter that information is out of date. The tryLock() method will give more reliable operation (note you can use this with a timeout as well)
EDIT #2: Example now includes tryLock()/unlock() for clarity.
I found this, we can use Thread.holdsLock(Object obj) to check if an object is locked:
Returns true if and only if the current thread holds the monitor lock on the specified object.
Note that Thread.holdsLock() returns false if the lock is held by something and the calling thread isn't the thread that holds the lock.
Whilst the above approach using a Lock object is the best way to do it, if you have to be able to check for locking using a monitor, it can be done. However, it does come with a health warning as the technique isn't portable to non Oracle Java VMs and it may break in future VM versions as it isn't a supported public API.
Here is how to do it:
private static sun.misc.Unsafe getUnsafe() {
try {
Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void doSomething() {
Object record = new Object();
sun.misc.Unsafe unsafe = getUnsafe();
if (unsafe.tryMonitorEnter(record)) {
try {
// record is locked - perform operations on it
} finally {
unsafe.monitorExit(record);
}
} else {
// could not lock record
}
}
My advice would be to use this approach only if you cannot refactor your code to use java.util.concurrent Lock objects for this and if you are running on an Oracle VM.
While the Lock answers are very good, I thought I'd post an alternative using a different data structure. Essentially, your various threads want to know which records are locked and which aren't. One way to do this is to keep track of the locked records and make sure that data structure has the right atomic operations for adding records to the locked set.
I will use CopyOnWriteArrayList as an example because it's less "magic" for illustration. CopyOnWriteArraySet is a more appropriate structure. If you have lots and lots of records locked at the same time on average then there may be performance implications with these implementations. A properly synchronized HashSet would work too and locks are brief.
Basically, usage code would look like this:
CopyOnWriteArrayList<Record> lockedRecords = ....
...
if (!lockedRecords.addIfAbsent(record))
return; // didn't get the lock, record is already locked
try {
// Do the record stuff
}
finally {
lockedRecords.remove(record);
}
It keeps you from having to manage a lock per record and provides a single place should clearing all locks be necessary for some reason. On the other hand, if you ever have more than a handful of records then a real HashSet with synchronization may do better since the add/remove look-ups will be O(1) instead of linear.
Just a different way of looking at things. Just depends on what your actual threading requirements are. Personally, I would use a Collections.synchronizedSet( new HashSet() ) because it will be really fast... the only implication is that threads may yield when they otherwise wouldn't have.
Another workaround is (in case of you didnt have chance with the answers given here )is using timeouts. i.e. below one will return null after 1 second hanging:
ExecutorService executor = Executors.newSingleThreadExecutor();
//create a callable for the thread
Future<String> futureTask = executor.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return myObject.getSomething();
}
});
try {
return futureTask.get(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
//object is already locked check exception type
return null;
}
I needed to also find a solution to this, so searched the Java Concurrency API and came across StampedLock. The project is using Java 8.
I am working in a heavily-threaded asynchronous data service that communicates with a native library and contains long-living configuration objects, necessitating sometimes-complex concurrency logic; thankfully this turned out to be relatively simple with the StampedLock class.
StampedLock has a method called tryOptimisticRead which does not wait, it just returns the status in the form of a long-time time stamp, where zero (0) indicates an exclusive lock is held. I then do delay for up to a second but you could just use the function without any sort of delay.
Here's how I'm detecting whether or not there's an exclusive lock, this paradigm is used in multiple locations and includes error handling:
int delayCount = 0;
//Makes sure that if there is data being written to this field at
// this moment, wait until the operation is finished writing the
// updated data.
while (data1StampedLock.tryOptimisticRead() == 0)
{
try
{
delay(WRITE_LOCK_SHORT_DELAY);
delayCount += 1;
}
catch (InterruptedException e)
{
logError("Interrupted while waiting for the write lock to be
released!", e);
Thread.currentThread().interrupt();
//There may be an issue with the JVM if this occurs, treat
// it like we might crash and try to release the write lock.
data1StampedLock.tryUnlockWrite();
break;
}
if (delayCount * WRITE_LOCK_SHORT_DELAY > TimeUnit.SECONDS.toMillis(1))
{
logWarningWithAlert("Something is holding a write lock on" +
" the data for a very, very long time (>1s). This may" +
" indicate a problem that could cause cascading" +
" problems in the near future." +
" Also, the value for the data that is about to be" +
" retrieved could potentially be invalid.");
break;
}
}
long nonExclusiveLockStamp = data1StampedLock.readLock();
Data data1NonVolatile = data1;
data1StampedLock.unlockRead(nonExclusiveLockStamp);
return data1NonVolatile;
The read locks on a StampedLock are non-exclusive and are like reading from a thread-safe Map or HashTable, where it is multi-read/single-write.
Here is how I am using the exclusive lock to communicate to other threads that the instance data is being written to:
long d1LockStamp = data1StampedLock.writeLock();
this.data1 = data1;
data1StampedLock.unlockWrite(d1LockStamp);
So if you wanted to only check whether or not something is locked at any given moment, you need only something simple like the following statement to get the status:
boolean data1IsLocked = data1StampedLock.tryOptimisticRead() == 0;
Then check the value of that boolean.
There are, of course, the caveats and Here Be Dragons information mentioned in other answers (namely that the information is immediately stale), but if you really need to lock something and check that lock from another thread, this seemed to me to be the most reasonable, safe, and effective way that uses the java.util.concurrency package with no external dependencies.
Thanks for this, it helped me out solving a race condition. I changed it a little to wear both belt and suspenders.
So here is my suggestion for AN IMPROVEMENT of the accepted answer:
You can ensure that you get safe access to the tryLock() method by doing something like this:
Lock localLock = new ReentrantLock();
private void threadSafeCall() {
boolean isUnlocked = false;
synchronized(localLock) {
isUnlocked = localLock.tryLock();
}
if (isUnlocked) {
try {
rawCall();
}
finally {
localLock.unlock();
}
} else {
LOGGER.log(Level.INFO, "THANKS! - SAVED FROM DOUBLE CALL!");
}
}
This would avoid the situation where you might get two calling tryLock() at the almost same time, causing the return to be potentially doubt full. I'd like to now if I'm wrong, I might be over cautios here. But hey! My gig is stable now :-)..
Read more on my development issues at my Blog.

Categories