当多个线程通过getter方法访问类字段时,如何保持线程安全? synchronized参数是否足够?
这是安全的吗?
public class SomeClass {
private int val;
public synchronized int getVal() {
return val;
}
private void setVal(int val) {
this.val = val;
}
}
或者是否会引入进一步的并发症?
答案 0 :(得分:17)
如果您也在此处使用setter上的'synchronized',则此代码是线程安全的。但是它可能不够细小;如果你有20个getter和setter并且它们都是同步的,你可能会创建一个同步瓶颈。
在这个特定的实例中,使用单个int变量,然后消除'synchronized'并将int字段标记为'volatile'也将确保可见性(每个线程在调用getter时将看到'val'的最新值)但是它可能无法满足您的需求。例如,期待
int old = someThing.getVal();
if (old == 1) {
someThing.setVal(2);
}
将val设置为2当且仅当它已经为1时才是错误的。为此,您需要一个外部锁或一些原子比较和设置方法。
我强烈建议您阅读Brian Goetz 等中的 Java Concurrency In Practice ,它具有Java的并发结构的最佳覆盖率。
答案 1 :(得分:3)
除了Cowan's comment之外,您还可以执行以下比较和存储:
synchronized(someThing) {
int old = someThing.getVal();
if (old == 1) {
someThing.setVal(2);
}
}
这是有效的,因为通过synchronized方法定义的锁与对象的锁(see java language spec)隐式相同。
答案 2 :(得分:2)
根据我的理解,你应该在getter和setter方法上使用synchronized,这就足够了。
编辑:这是link以获取有关同步的更多信息,而不是。
答案 3 :(得分:1)
如果您的类只包含一个变量,那么实现线程安全的另一种方法是使用现有的AtomicInteger对象。
public class ThreadSafeSomeClass {
private final AtomicInteger value = new AtomicInteger(0);
public void setValue(int x){
value.set(x);
}
public int getValue(){
return value.get();
}
}
但是,如果添加其他变量以使它们相关(一个变量的状态取决于另一个变量的状态),则AtomicInteger将不起作用。
回应建议,阅读“Java Concurrency in Practice”。
答案 4 :(得分:0)
对于简单的物体,这可能就足够了。在大多数情况下,您应该避免使用synchronized关键字,因为您可能会遇到同步死锁。
示例:
public class SomeClass {
private Object mutex = new Object();
private int val = -1; // TODO: Adjust initialization to a reasonable start
// value
public int getVal() {
synchronized ( mutex ) {
return val;
}
}
private void setVal( int val ) {
synchronized ( mutex ) {
this.val = val;
}
}
}
确保只有一个线程读取或写入本地实例成员。
阅读“Java中的并行编程(tm):设计原则和模式(Java(Addison-Wesley))”一书,也许http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html也很有用......
答案 5 :(得分:-3)
存在同步以防止线程干扰和内存一致性错误。通过在getVal()上进行同步,代码可以保证SomeClass上的其他同步方法也不会同时执行。由于没有其他同步方法,因此没有提供太多价值。另请注意,对基元的读取和写入具有原子访问权限。这意味着通过仔细编程,不需要同步对字段的访问。
不确定为什么会降到-3。我只是总结一下Sun的同步教程(以及我自己的经验)。
使用简单的原子变量访问是 比访问这些更有效 变量通过同步代码, 但需要更多的照顾 程序员避免内存一致性 错误。是否额外的努力 值得取决于大小和 应用程序的复杂性。