Tin*_*wor 10 java multithreading atomic synchronized
AtomicReference和Synchronized之间有什么区别吗?
例如
public class Internet {
AtomicReference<String> address;
public String getAddress(){
return address.toString();
}
public void setAddress(String address) {
this.address.set(address);
}
}
Run Code Online (Sandbox Code Playgroud)
我将类传递给一些尝试同时使用该类的线程,如果我使用它是同样的事情:
public class Internet {
String address;
public String getAddress(){
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Run Code Online (Sandbox Code Playgroud)
然后在线程使用synchronized
之前访问类?
您没有在第一个示例中初始化引用,它可能应该是:
public class Internet {
AtomicReference<String> address = new AtomicReference<String>();
public String getAddress(){
String s = address.get();
return s == null ? null : s.toString();
}
public void setAddress(String address) {
this.address.set(address);
}
}
Run Code Online (Sandbox Code Playgroud)
访问限制所在的位置很重要.如果你把控件放在被访问的对象中,那么它可以单独控制它的不变量,这比依赖线程正确地进行所有同步要脆弱得多,其中一个行为不当的访问线程可能破坏被访问的东西.所以第一个例子在该帐户上要好得多.
如果您更改第二个示例,以便对象可以控制自己的锁定(因此它不依赖于访问它的线程来安全地执行此操作),如下所示:
public class Internet {
private final Object lock = new Object();
private String s;
public String getAddress() {
synchronized(lock) {
return s;
}
}
public void setAddress(String s) {
synchronized(lock) {
this.s = s;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后它是一个更接近的比较,一个依赖于锁定而另一个依赖于原子引用.使用AtomicReference的那个尝试使用机器级原子处理指令来避免锁定.哪个更快可能取决于您的硬件和jvm以及处理负载,通常原子方法应该更快.同步方法是一种更通用的机制; 使用synchronized块,您可以更轻松地将多个分配组合在一起,其中使用原子引用更加复杂.
正如詹姆斯在他的回答中所说,在同步时你的线程正在等待锁定; 没有超时,死锁是可能的.使用原子引用,线程进行更改而不等待共享锁.
实现这一目标的最简单且性能最佳的方法是组织代码,以便可以使对象不可变,这样就可以避免所有锁定,忙等待和缓存更新:
public final class Internet {
private final String s;
public Internet(String s) {
this.s = s;
}
public String getAddress() {return s;}
}
Run Code Online (Sandbox Code Playgroud)
按优先顺序降序排列:
如果您能理解这些答案,那么这里的其他答案并没有什么问题,但它们似乎主要集中在细节、术语和用例上,而跳过了“每个人”已经知道的大局。
这是大图——AtomicFoobar
操作和synchronized
块之间的区别。
AtomicFoobar 操作(例如,atomicReference.compareAndSet(...))要么只执行一个非常简单的线程安全操作,要么失败。无论成功还是失败,它都不会让线程等待。
synchronized
另一方面,一个块和你做的一样复杂——在锁被锁定时执行的语句数量没有限制。一个synchronized
块将永远不会失败,但是它可以使调用线程等待,直到操作(一个或多个)可以安全地进行。
在大多数体系结构中,每个 AtomicFoobar 方法都作为 Java本地方法(即 C 代码)实现,该方法执行单个专用硬件指令。另一方面,同步通常是通过操作系统调用来实现的,这些调用在内心深处可能使用相同的硬件指令。