AtomicReference和Synchronized之间有什么区别吗? E.G。
public class Internet {
AtomicReference<String> address;
public String getAddress(){
return address.toString();
}
public void setAddress(String address) {
this.address.set(address);
}
}
我将类传递给一些尝试同时使用该类的线程,如果我使用它是同样的事情:
public class Internet {
String address;
public String getAddress(){
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
然后在线程中使用synchronized
才能访问类?
答案 0 :(得分:9)
你没有在第一个例子中初始化引用,它应该是:
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);
}
}
访问限制的位置很重要。如果你把控件放在被访问的对象中,那么它可以单独控制它的不变量,这比依赖线程正确地进行所有同步要脆弱得多,其中一个行为不当的访问线程可能破坏被访问的东西。所以第一个例子在该帐户上要好得多。
如果更改第二个示例,以便对象可以控制自己的锁定(因此它不依赖于访问它的线程安全地执行此操作),如下所示:
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;
}
}
}
然后它进行了更接近的比较,一个依赖于锁定而另一个依赖于原子引用。使用AtomicReference的那个尝试使用机器级原子处理指令来避免锁定。哪个更快可能取决于您的硬件和jvm以及处理负载,通常原子方法应该更快。同步方法是一种更通用的机制;使用synchronized块,您可以更轻松地将多个分配组合在一起,其中使用原子引用它涉及更多。
As James says in his answer,同步您的线程正在等待锁定;没有超时,死锁是可能的。使用原子引用,线程在没有等待共享锁的情况下进行更改。
实现这一目标的最简单,性能最佳的方法是组织代码,以便可以使对象不可变,这样就可以避免所有锁定,忙等待和缓存更新:
public final class Internet {
private final String s;
public Internet(String s) {
this.s = s;
}
public String getAddress() {return s;}
}
按优先顺序降序:
答案 1 :(得分:4)
这里的其他答案没有任何问题如果你可以理解它们,但它们似乎主要关注细节,术语和用例,同时跳过“每个人”的大局已经知道了。
以下是全局图--- AtomicFoobar
操作与synchronized
块之间的区别。
AtomicFoobar操作(例如,atomicReference.compareAndSet(...))要么执行一个非常简单的线程安全操作,要么失败。无论是成功还是失败,它都不会让线程等待。
另一方面,synchronized
块与您所做的一样复杂 - 锁定锁定时执行的语句数量没有限制。 synchronized
块永远不会失败,但可能使调用线程等待,直到可以安全地执行操作。
在大多数体系结构中,每个AtomicFoobar方法都实现为Java 本机方法(即C代码),它执行单个专用硬件指令。另一方面,同步最常用操作系统调用来实现,这些操作系统调用可能会使用相同的硬件指令。
答案 2 :(得分:2)
当一个线程正在执行该方法时,synchronized
方法/块阻止从其他线程对该方法/块的所有访问。
许多线程可以同时访问Atomic...
- 通常有CAS种访问方法可以帮助他们进行高速访问。
因此 - 它们完全不同,但它们有时可用于解决并行可访问性问题。
这两个类使用两种不同的方法返回一个稳定增加的数字,这样相同的数字永远不会被传递两次。 AtomicInteger
版本将在高负载环境中运行得更快。使用synchronized
的人将使用Java 4及更早版本。
public class Incremental1 {
private AtomicInteger n = new AtomicInteger();
public Integer nextNumber() {
// Use the Atomic CAS function to increment the number.
return n.getAndIncrement();
}
}
public class Incremental2 {
private int n = 0;
public synchronized Integer nextNumber() {
// No two threads can get in here at the same time.
return n++;
}
}