繁体   English   中英

同步代码块是仅阻塞分配还是整个块体?

[英]Do synchronized code blocks only block for assignments or for the entire block body?

我有一个数据var, monthArray ,该数据由多个使用者读取,并由一个periodallall预定的更新程序线程定期进行更新。 全部异步。

我考虑了这两个选项,以安全地执行更新。

    ArrayList<String> tempArray = ModelJob.getDistinctMonths(user, true);       
    synchronized (monthArray) {
        monthArray = tempArray;
    }

要么

    synchronized (monthArray) {
        monthArray = ModelJob.getDistinctMonths(user, true);
    }

第一个背后的想法是ModelJob.getDistinctMonths(user, true); 调用非常耗时,我不想将synchrinzation保留得更长,而只需要使用更新后的数组快速重新分配旧数组即可。 但是似乎很困惑,我只想在完全必要的时候这样做。 谁能给我任何关于jvm如何处理这种同步和天气的见解,或者不这样做会给我性能的提高吗? 基本上,我问jvm是否会阻止整个静态ModelJob调用,或者它是否能够仅通过阻止重新分配而逃脱并且是安全的,如果是,那么这样做是否足够聪明。

假设你不需要周围的同步getDistinctMonths()调用(该调用是线程安全的,你不需要调用和赋值周围的原子),那么你可以分配周围刚刚同步(是的,阻止仅作用于同步块,否则语法将毫无意义。 注意,@ JohnVint提出了一个好处,即您不应该在修改monthArray引用时对其进行同步。 您必须在一个不变的单独对象实例上进行同步。

最后,您可以删除同步块,并使monthArray成员易失,并获得相同的结果。

如果仅将volatile修饰符放在monthArray并删除所有synchronized块, monthArray具有无锁线程安全性。

另外,JVM可能会优化您的更干净(第二个)版本的代码,使其像第一个版本一样执行。 因此,如果保持锁定状态,最好坚持使用清洁版本。

从性能的角度来看,使用第一种方法会更好。 它将避免不必要的同步。

您必须记住的一件事是,即使对monthArray的读取也需要进行同步。 同步仅在使用相同的对象锁同步更新和读取时才起作用。 我宁愿使用类对象锁。 例如,如果此代码是ModelUpdate类的一部分,请使用以下代码

synchronized(ModelUpdate.class) {
        monthArray = tempArray;
}

同步块将始终对其整个执行进行阻塞。 作为参数给出的对象(在您的情况下为monthArray)被称为“监视器”,它将保证与对象(monthArray)具有相同参数的所有其他同步块将被异步执行。

这里一个明显的缺陷是您不应在将要更改的对象上进行同步。

我更喜欢第一个示例,而是使用通用锁

final Object lock = new Object();

synchronized(lock){
   monthArr = ...;
}

但是,正如大多数人所说,声明monthArr volatile将具有相同的效果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM