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
在进入课堂之前?
您没有在第一个示例中初始化引用,它可能应该是:
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 以及处理负载,通常原子方法应该更快。同步方法是一种更通用的机制;使用同步块,您可以更轻松地将多个分配组合在一起,而使用原子引用则涉及更多。
正如詹姆斯在回答中所说,通过同步,您的线程正在等待锁;没有超时,并且可能出现死锁。通过原子引用,线程无需等待共享锁即可进行更改。
实现这一点的最简单且性能最佳的方法是组织代码,以便使对象不可变,从而避免所有锁定、忙等待和缓存更新:
public final class Internet {
private final String s;
public Internet(String s) {
this.s = s;
}
public String getAddress() {return s;}
}
按优先顺序降序排列:
- 尽可能选择不变性。
- 对于不能不可变的代码,请尝试将更改限制在线程中。
- 如果只有一件事需要跨线程更改,请使用原子方法。
- 如果跨线程的多个更改需要一起发生而不受其他线程的干扰,请使用锁定。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)