局部变量同步的必要性
在JSON-java库( org.json.JSONArray )中,我发现这个代码片段带有一个围绕方法局部变量的synchronized
块
public String toString(int indentFactor) throws JSONException { StringWriter sw = new StringWriter(); synchronized (sw.getBuffer()) { return this.write(sw, indentFactor, 0).toString(); } }
我不明白这里同步的必要性,因为StringWriter
只是给定方法的本地(以及为什么同步在Buffer上)。 这里的同步是否真的有必要,如果,为什么?
这可能是性能优化。 在oracle jvm中,重新获取已经锁定的锁定速度非常快。 据推测, write
调用会对StringBuffer进行大量调用。 通过在调用write
之前锁定,锁定将通过所有这些调用保持,而不是为每次调用释放和重新获取。
StringWriter
的空构造函数是
/** * Create a new string writer using the default initial string-buffer * size. */ public StringWriter() { buf = new StringBuffer(); lock = buf; }
没有任何共享,因此不需要synchronized
块。
除非…… write
代表write
另一个线程,但我对此表示怀疑。
getBuffer()
返回一个StringBuffer
,根据文档, StringBuffer
已经同步:
字符串缓冲区可供多个线程使用。 这些方法在必要时进行同步,以便任何特定实例上的所有操作都表现得好像它们以某个串行顺序出现,这与所涉及的每个单独线程所进行的方法调用的顺序一致。
这意味着在StringBuffer
上再次同步是完全矫枉过正的。 对StringWriter
更改将自动同步,因为它在内部使用同步的StringBuffer
。
由于StringWriter
实例是方法调用的本地实例,因此不可能让多个线程同时访问同一个实例,这也使得不需要进行同步。
这是一个错误。 每个线程在方法中创建自己的局部变量并在其上进行同步。每次进入方法线程时都会创建自己的对象监视器,这些对象监视器不能被另一个线程保存,因为它是本地的并且只存在于线程的堆栈中!