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);
Related
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.
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.
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.)
I want the server to execute a certain part of the service impl code for one client at a time, thread-safe; and sequentially. Here's the part of the server-side service implementation that does this:
public BorcData getBorcData(String userId) throws GeneralException, EyeksGwtException
{
StoredProcedure sp = DALDB.storedProcedure("BORCBILDIRIM_GETMUKDATA_SP");
DALResult spResult;
Row spRow;
String vergiNo;
String asamaOid;
synchronized (ServerUtility.lock_GeriArama_GetBorcData_GetMukDataSP)
{
String curOptime =CSDateUtility.getCurrentDateTimeToSave();
sp.addParam(curOptime);
spResult = sp.execute();
if (!spResult.hasNext())
{
throw new GeneralException("53", "");
}
}
You see the synchronized block. The object that I use for the lock is defined as:
public static Object lock_GeriArama_GetBorcData_GetMukDataSP = new Object();
My problem is: I think I saw that while a client was waiting to execute that synchronized block for a long time, some other client called this service and executed that block without getting in line and went on. The first client was still waiting.
I know that the server-side runs pure Java. Is it possible that the server-side is being unfair to the clients and not running the longest waiting client's request first?
EDIT: Actually; the fairness isn't even the real problem. Sometimes clients look like they just hang in that synchronized part; waiting forever for the service to finish.
First your lock Object always should be declared final. This isn't fixing any problems, but it tells you if you did code something wrong (like setting the lock to a different lock somewhere).
One way to ensure fairness is to use a ReentrantLock initialized with true (fair scheduling). It will ensure that clients do not hang indefinitely, but are executed in a FIFO order. The good thing is that this requires only a minor change to your code, by replacing all those synchronized blocks with:
lock.lock();
try {
// previous code
} finally {
lock.unlock();
}
The finally is just a safety measure, should any part inside throw an exception.
Other than that your code looks perfectly fine, so the issue is most likely in the DB and not caused by using synchronized at all.
Multi threading in java doesn't guarantee sequential execution.
Read the article : http://www.javaworld.com/javaworld/jw-07-2002/jw-0703-java101.html
It is much helpful in understanding how threads are scheduled.
As you can tell I'm new to multithreading and a bit stuck here. For my program I need a thread (PchangeThread in the below example) that can be toggled on and off from another thread at any point during execution of the program.
The thread should be suspended on start and resume when pixelDetectorOn() is called.
The two threads will most likely not need to share any data except for a start/stop flag. I included a reference to the main thread anyway, just in case.
However, in the below code the only message that is ever output is "before entering loop", which indicates that the thread never wakes up from wait() for some reason. I'm guessing this is some kind of locking problem but I haven't been able to figure out what exactly is going wrong. Locking on this.detector from the main thread gives me the same result. Also I'm wondering if the wait()/notify() paradigm is really the way to go for suspending and waking the thread.
public class PchangeThread extends Thread {
Automation _automation;
private volatile boolean threadInterrupted;
PchangeThread(Automation automation)
{
this._automation = automation;
this.threadInterrupted = true;
}
#Override
public void run()
{
while (true) {
synchronized (this) {
System.out.println("before entering loop");
while (threadInterrupted == true) {
try {
wait();
System.out.println("after wait");
} catch (InterruptedException ex) {
System.out.println("thread2: caught interrupt!");
}
}
}
process();
}
}
private void process()
{
System.out.println("thread is running!");
}
public boolean isThreadInterrupted()
{
return threadInterrupted;
}
public synchronized void resumeThread()
{
this.threadInterrupted = false;
notify();
}
}
resumeThread() is called from the main thread the following way:
public synchronized void pixelDetectorOn(Context stateInformation) {
this.detector.resumeThread();
}
detector is a reference to an instance of PchangeThread.
The "detector"-thread is instantiated in the program's main module the following way:
detector=new PchangeThread(this);
As you said, you need to protect access to the shared flag. You declared threadInterrupted volatile, but than are still using syncronized. You only need one. I prefer to just use syncronized as it makes things simpler. Multi-threading is complicated enough, keep it simple unless you know you need more complicated controls. This means that any time threadInterrupted is read or written to, the access should be synchronized. Currently, you are not doing that in setThreadInterrupt() and isThreadInterrupted().
Secondly, you want to synchronize on as small of a code block as possible. Inside of run(), you are synchronizing over the inner loop. In actuality, you only need to to synchronize on the read of threadInterrupted. When the implementation of isThreadInterrupted() is fixed as mentioned above, you can use that directly and remove the synchronized block from the inner loop.
The fact that you are synchronizing on the inner loop, is the error that is causing your code to never print "thread is running!". PchangeThread acquires the lock on itself and calls wait() to suspend the thread. However, the thread is still holding the lock at this point. At some point later, the main thread calls resumeThread() in order to restart the thread. However, that method can not begin its execution because it must first wait to acquire the lock. However, it will never get the lock until the PchangeThread is notified.
You are providing two ways to set threadInterrupted, but only one of them notifies the thread when the value is set to false. Do you really need setThreadInterrupt()? I expect you don't. If you keep it, it should act the same as resumeThread() when the argument is false.
Lastly, it is better to lock on a private object instead of the instance itself. You have complete control over the private lock object. However, anyone with a reference to your thread instance could also use it as the lock for a synchronized block, which could potentially lead to a hard to find deadlock.
Your code altered to use my edits:
public class PchangeThread extends Thread {
private final Object _lock = new Object();
Automation _automation;
private final boolean _threadInterrupted;
PchangeThread(Automation automation)
{
_automation = automation;
_threadInterrupted = true;
}
#Override
public void run()
{
while (true) {
System.out.println("before entering loop");
while (isThreadInterrupted()) {
try {
wait();
System.out.println("after wait");
} catch (InterruptedException ex) {
System.out.println("thread2: caught interrupt!");
}
}
process();
}
}
private void process()
{
System.out.println("thread is running!");
}
public boolean isThreadInterrupted()
{
synchronized (_lock) {
return _threadInterrupted;
}
}
public void resumeThread()
{
synchronized (_lock) {
_threadInterrupted = false;
notify();
}
}
}
I personally would ask myself the following question in this case: Is the
isInterrupted
flag set only by the main thread e.g. the worker thread just reads it and decides whether to wait or not based on the flag BUT doesn't update it. Or can it be set by both the main thread and the worker thread.
If it is the former - go for a volatile boolean. That way the worker thread will not cache the volatile's value and will always read it from memory. This won't create a race condition because only 1 thread will be updating it - the main one. Think of it as a publish/subscribe scenario.
If you scenario falls in the latter category - use an AtomicBoolean variable. Both cases are going to be more efficient than the synchronized keyword, since you won't acquire any locks but in the case of Atomic* variables you will be utilizing CAS operations which are more lightweight than lock acquisition.
Your code is not wrong (though is not ideal).
I ran it and it prints all the expected messages. Likely, you just do not invoke resumeThread().
A couple of advises:
do not sync on Thread, make a Runnable and sync on it.
you want to start some computation, but what are the data to compute? Looks like they go in a separate way. This is a ground for errors. Use single channel for both data and control. The preferred way is to use a Queue for such a channel. For example, LinkedBlockingQueue is already synchronized in a proper way.
I doubt that anyone will read this, but just in case someone's interested in knowing:
When I checked the debugger log I noticed something strange - it read "debugging stopped on uncompilable source code: )Void;". Since I couldn't think of anything in my source that could have caused this error , I guessed that Netbeans had a problem with some part of the external code I was using (it was not caused by a breakpoint and the project compiled fine!). So, I just updated the third party library I'm using to it's latest version. And behold: after that I suddenly got a null pointer exception when I called resumeThread()!. I checked the rest of my code and quickly found the bug (indeed the reference to the thread was null).
So, to sum it up: The strange behaviour was caused by a minor bug in my program, but something in the external jar led to the suppression of the exception that should have been thrown. Just out of curiosity I double checked by downgrading the jar and "unfixing" the bug and again, the exception was swallowed and the debugger exited with the above mentioned strange message.
Netbeans version 7.1.1