0

I have the following method which is being called by multiple threads:

private final static Object lock = new Object();
public String createDirectory()
{
    File file = new File("D:"+File.separator+"test");
    if(!file.exists() || !file.isDirectory())//if file doesn't exist then create a new directory.
    {
        synchronized(lock)
        {
            if(!file.exists() || !file.isDirectory())//----> (1)
            {
                boolean isCreated = file.mkdir();
            }
        }
    }
    return file.getAbsolutePath();
}

Is it possible that the JVM optimizer will comment out the code marked as (1) in above given menthod? I am suspecting that because, the existence of directory is checked twice in immediate succession. Considering it as a unnecessary redundant checking JVM optimizer might comment out the line --> (1).

15
  • 2
    The JVM can never optimize away expressions involving method calls because it doesn't know if those method calls have side effects. Commented Jun 17, 2014 at 20:59
  • 1
    A JVM Only ever optimizes BYTECODE not java code. It optimizes by taking comon java patterns and mapping them to more efficient bytecode forms. It never "optimizes your java" cubrid.org/blog/dev-platform/understanding-jvm-internals Commented Jun 17, 2014 at 21:03
  • 2
    @DaoWen Not necessarily. If a function is known not to have any side effects, it can be optimized out. A trivial case is boolean doNothing() {return true;}. But in this case, your statement is true, because the File methods are going to eventually end up as OS calls, and the JVM can't assume those don't have side effects (and aren't affected by state other than their arguments). Commented Jun 17, 2014 at 21:22
  • 2
    @Mac Definitely. First, the methods can be inlined; the code in the methods is "copy-pasted" to the call site, thus saving on the overhead of calling the method. Also, if the method doesn't have any side effects and always returns the same value (or possibly returns a different value, but that value is never used -- I'm not sure how far the optimizations go, to be honest), the method can be removed altogether. You can see an example at gist.github.com/yshavit/73d4bb96dcdaecd652d8. If the JVM didn't optimize the methods out, that'd take a long time. Commented Jun 17, 2014 at 21:36
  • 1
    @Mac It's not just the redundant calls, it'd be if each redundant call could be proven to do nothing. But basically the general rule of an optimizer is, "if you can tell it's there except by seeing that the method runs faster, then it's broken." Commented Jun 17, 2014 at 21:59

3 Answers 3

1

No. It will not be optimized out.

It would be a bit rubbish if the JVM optimized out a standard double check lock pattern.

Sign up to request clarification or add additional context in comments.

Comments

1

No. Compiler optimizations don't alter a program's flow. Specifically, method invocations will never be skipped.

Comments

1

As pointed out by @yshavit

Because the File methods are going to eventually end up as OS calls, and the JVM can't assume those don't have side effects (and aren't affected by state other than their arguments) so, the JVM will not optimize the code involving if(!file.exists() || !file.isDirectory()) by commenting out that section .

7 Comments

The JVM does not operate in terms of method invocations. It will inline the code of the called method and optimize the resulting code. Thus, when it detects that within the code the same variables are read without an in-between write nor thread synchronization, it might join multiple reads into a single read. Since java.io.File maintains a cache that lasts about a minute or so, two exists calls on the same File within a short time span are very unlikely to result in two OS calls.
@Holger So according to you there is a possibility that both the exists invocations on File would result in same value even though the File existence state is changed while in between the two calls?
I encountered that issue in the past and had to insert a wait to notice an external change. But keep in mind that this is only relevant to external changes where your synchronized statement has no relevance anyway. Regarding threads within your JVM your code is safe as the JVM might optimize doubled operations but will not remove the effects of proper synchronization. If there is a possibility that a thread leaving the synchronized statement has altered the state, a thread entering a synchronized block using the same lock instance must re-read the state.
Correct me if I am wrong..In nutshell I can be assured that the two calls to exist method on File will definitely show the latest state of File because there is a synchronization involved in between the two calls.
Just for clarity: synchronization is only relevant for changes within the JVM made by threads synchronizing on the same instance. For these, the second call (within the synchronized block) is guaranteed to read the most recent value.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.