当前位置: 首页 > 知识库问答 >
问题:

getters和setters应该同步吗?

何辰沛
2023-03-14
private double value;

public synchronized void setValue(double value) {
    this.value = value;
}
public double getValue() {
    return this.value;
}

在上面的例子中,让吸气剂同步有什么意义吗?

共有3个答案

徐瀚
2023-03-14

这里的原因是防止任何其他线程在一个线程读取时更新该值,从而避免对陈旧值执行任何操作。

在这里,get方法将获取“this”上的固有锁,因此任何其他可能尝试使用setter方法设置/更新的线程都必须等待获取“this“上的锁,才能进入执行get的线程已经获取的setter方法。

这就是为什么建议在可变状态上执行任何操作时遵循使用相同锁的实践。

由于没有复合语句,因此使字段不稳定将在这里起作用。

重要的是要注意,同步方法使用内部锁,即“this”。因此,获取和设置两者同步意味着进入该方法的任何线程都必须对此进行锁定。

当执行非原子64位操作时,应特别考虑。Java Concurrency In Practice的摘录有助于理解这种情况-

Java内存模型要求读取和存储操作是原子性的,但是对于非易失性的long和double变量,允许JVM将64位读取或写入视为两个独立的32位操作。如果读取和写入发生在不同的线程中,则有可能读取一个非易失性long并获得一个值的高32位和另一个值的低32位。因此,即使您不关心过时的值,在多线程程序中使用共享的可变long和double变量也是不安全的,除非它们被声明为volatile或由锁保护。”

柯冯浩
2023-03-14

让我通过例子向您展示JIT编译代码的合法方式。你写道:

while (myBean.getValue() > 1.0) {
  // perform some action
  Thread.sleep(1);
}

JIT编译:

if (myBean.getValue() > 1.0) 
  while (true) {
    // perform some action
    Thread.sleep(1);
  }

在稍微不同的场景中,即使是Java编译器也可以产生相似的字节码(它只需要消除动态调度到不同getValue的可能性)。这是一个提升的教科书示例。

为什么这是合法的?编译器有权假设 myBean.getValue() 的结果在执行上述代码时永远不会改变。如果不同步,则允许忽略其他线程的任何操作。

甄成弘
2023-03-14

我认为最好在这里引用Java并发实践:

假设仅在写入共享变量时才需要使用同步是一个常见的错误;这根本不是真的。

对于可以由多个线程访问的每个可变状态变量,对该变量的所有访问都必须在持有相同锁的情况下执行。在这种情况下,我们假设变量由该锁保护。

在没有同步的情况下,编译器、处理器和运行时会对操作的执行顺序做一些非常奇怪的事情。试图推理内存操作“必须”在不充分同步的多线程程序中发生的顺序几乎肯定是不正确的。

通常情况下,您不必对原语如此小心,因此如果这是一个<code>int</code>或<code>boolean</code<,则可能是:

当线程在没有同步的情况下读取变量时,它可能会看到一个过时的值,但至少它看到一个由某个线程实际放置在那里的值,而不是某个随机值。

然而,对于64位操作,例如在Long上,如果它们没有声明易失性,则情况并非如此:

Java内存模型要求读取和存储操作是原子的,但是对于非易失的长整型和双精度变量,JVM可以将64位读取或写入作为两个独立的32位操作来处理。如果读取和写入发生在不同的线程中,那么读取一个非易失性long并获得一个值的高32位和另一个值的低32位是可能的。

因此,即使您不关心陈旧的值,在多线程程序中使用共享可变长变量和双变量也不安全,除非它们被声明为易失性或由锁保护。

 类似资料:
  • 我正在spring boot创建我的API。我认为一个产品是由以下部件组成的: 这里是我的代码:(实体层) } 下面是我的Controller类: } 我的问题: 在实体类“Product”中,对于类型为List的productComponents变量,getter和setter应该如上面所述,还是应该如下所示: 并将controller类中的update方法更改为: 还是有更好的解决方案?

  • 对于此代码 kotlin编译器生成: 即使属性没有自定义getter或setter。可以使用注释删除冗余的get和set方法。所以这段代码 仅生成一个字段,无需其他方法。 但是有没有办法让kotlin编译器不为整个项目中的所有属性生成getter和setter?不管它是否有注释。也许是一些实验性编译器标志? 我想要它是因为我在kotlin上编写了android仪器测试。测试apk超过65k方法计数

  • 对于这个程序,实例变量的创建和模型需要是一个字符串,价格需要是我已经有的两倍,但不确定如何处理需要是int类型的年份,大于1900。然后我需要用参数做一个构造函数,我也做了,但是toString需要用setter和getters方法返回Car对象的字符串表示。所以我在试图为setter想出一些东西时遇到了问题,如果我做对了这一部分。 这部分是Cartest驱动程序,我不确定我这样做是否正确。我必须

  • 我对Lombok和JSTL如何处理getters和setters有点困惑。我有以下@data类: 并且我可以访问.jsp中的私有布尔值,如下所示: 同时我也可以将私有布尔值声明为 并以相同的方式在JSTL中访问它。但是,以下代码将引发PropertyNotFoundException: 谁能澄清一下我在同时使用JSTL和Lombok时应该使用什么命名约定吗?提前道谢!

  • 问题内容: 我目前正在使用几种不同模式用Java开发一个简单的游戏。我扩展了Game类的主要内容,以将主要逻辑放入其他类中。尽管如此,主要的游戏类别仍然相当庞大。 快速浏览一下我的代码后,其中大部分是Getters和Setters(60%),而游戏逻辑真正需要的其余部分则是Getters和Setters。 Google的一些搜索声称Getters和Setters是邪恶的,而其他一些人则声称它们是良