让我们假设有人同步一个返回int的方法:
int whatever = 33;
...
public synchronized int getWathever() {
return this.whatever;
}
我们从Java规范中了解到,int是自动修改的。因此,synchronized
语句不是必需的。
编译器会删除/优化吗?
答案 0 :(得分:7)
synchronized除了获得锁定之外还有其他线程安全效果(确保修改后的数据对其他线程可见)
只要这些副作用有效,JIT基本上可以自由地做它想做的事情
虽然在示例中它必须确保在加载变量期间任何其他线程都不会保持锁定,这最容易通过有效获取锁定来确保
答案 1 :(得分:7)
不,这根本不可能。如果编译器和JVM这样做,很可能会违反 Java编程语言内存模型设置的约束。
更具体地说,违反了Java语言规范中规定的 synchronization order 顺序。如果编译器或JVM * 要删除任何“不需要的”同步,那么执行的任何进一步优化都将违反开发人员对同步顺序(以及之前发生的)关系所做的任何假设。在您的特定情况下,在读取之前,在遵循Java内存模型的编译器/ JVM中,将对整数进行任何写入。
删除同步的编译器/ JVM只会导致违反内存模型的环境。例如,可以在读取整数值之前不使编译器/ JVM放置内存屏障的情况下执行方法内联,从而允许从缓存值中读取过时值。
* 注意,对编译器/ JVM二重奏的引用是有意的。编译器只会发出符合JLS的字节码; JVM可能只会出现一个错误,即仍然可能违反内存模型的要求。为了完整的内存模型,编译器和JVM都应该符合内存模型设置的要求。
答案 2 :(得分:5)
有些情况下VM可以消除锁定。例如
逃生分析
int bar()
Foo foo = new Foo();
return foo.getWhatever();
VM可以推断foo对任何其他线程都不可见,因此没有其他人会尝试锁定它,因此可以删除getWhatever
方法的锁定。
锁定粗化
Foo foo = ...;
void bar()
a();
foo.getWhatever();
b();
foo.getWhatever();
c();
可以合法合并以保存一个锁定操作
void bar()
synchronized(foo)
a();
foo.getWhatever_without_lock();
b();
foo.getWhatever_without_lock();
c();
另一个好消息是,由于锁定区域太短,由于自适应锁定,VM很可能会使用自旋锁定;由于锁定失败导致的线程暂停是不太可能的。
答案 3 :(得分:4)
除非你确保int变量以某种其他方式正确地同步到主内存,否则删除那个“synchronized”绝对是不安全的,除非你确保int变量与主内存正确同步,所以在这种情况下,没有。