开发者

Does java remove/optimize unnecessary synchronized statements?

开发者 https://www.devze.com 2023-03-28 08:20 出处:网络
Let\'s imagine someone synchronizes a method returning an int: int whatever = 33; ... public synchronized int getWathever() {

Let's imagine someone synchronizes a method returning an int:

int whatever = 33;
...

public synchronized int getWathever() {
    return this.whatever;
}

We know from Java specs that ints are modified atomically. Hence, the synchronized statement is not nec开发者_如何学编程essary.

Will the compilers remove/optimize it?


No, that simply is not possible. If the compiler and the JVM were to do so, it is likely that the constraints set by the Java programming language memory model would be violated.

More specifically, the synchronization order order stated in the Java Language Specification would be violated. If a compiler or a JVM* were to remove any "unwanted" synchronizations, then any further optimizations performed would violate any assumptions placed by a developer on the synchronization order (and the happens-before) relationship. In your specific case, any write to the integer will happen before the read, in a compiler/JVM that obeys the Java memory model.

A compiler/JVM that removes the synchronizations would simply result in an environment where the memory model is violated. For example, method in-lining could be performed without the compiler/JVM placing a memory barrier before the read of the integer value, thereby allowing for stale values to be read from a cached value.

* Note, the reference to the compiler/JVM duo is intentional. A compiler will only emit bytecode that complies with the JLS; a JVM could simply have a bug where the requirements of the memory model could still be violated. For the sake of completeness of the memory model, both the compiler and the JVM should comply with the requirements set by the memory model.


synchronized has other thread safety effects besides getting a lock (ensuring the modified data is visible to other threads for one)

as long as these side effects are valid the JIT is essentially free to do what it wants

though in the example it has to ensure the lock is not held by any other thread during the loading of the variable which is easiest to ensure by effectively getting the lock


There are cases when VM can eliminate a lock. For example

Escape analysis

int bar()
    Foo foo = new Foo();
    return foo.getWhatever();

VM can reason that foo is not visible to any other thread, therefore nobody else will try to lock it, therfore locking of the getWhatever method can be dropped.

Lock Coarsening

Foo foo = ...;
void bar()
    a();
    foo.getWhatever();
    b();
    foo.getWhatever();
    c();

can be legally merged to save one locking action

void bar()
    synchronized(foo)
        a();
        foo.getWhatever_without_lock();
        b();
        foo.getWhatever_without_lock();
        c();

Another good news is since the locked region is so short, due to adaptive locking, VM most likely will use spin lock for it; thread suspension due to failed locking is very unlikely.


It's absolutely not safe to remove that "synchronized" if the intent is to make it thread-safe unless you ensure the int variable is properly synchronized to main memory in some other way, so in this case, no.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号