Goetz的"Java Concurrency in Practice"第3.2.1节包含以下规则:
this在施工期间不要让参考物逃逸
我的理解是,在一般情况下,允许this以逃避可能导致其他线程看到您的对象不完全构建版本和违反的初始化安全保障final领域(如讨论如这里)
但是有可能安全泄漏this吗?特别是,如果你happen-before在泄漏之前建立关系?
例如,官方执行官Javadoc说
在将
Runnable对象提交到一个Executor发生之前的一个线程中的操作- 在它执行开始之前,可能在另一个线程中
我对Java内存模型的天真阅读理解是,类似下面的内容应该是安全的,即使它this在构造函数结束之前泄漏:
public final class Foo {
private final String str1;
private String str2;
public Foo(Executor ex) {
str1 = "I'm final";
str2 = "I'm not";
ex.execute(new Runnable() {
// Oops: Leakage!
public void run() { System.out.println(str1 + str2);}
});
}
}
Run Code Online (Sandbox Code Playgroud)
也就是说,即使我们已经泄漏this到潜在的恶意Executor,泄漏 …
我正在尝试实现线程安全的Map缓存,并且希望对缓存Strings进行延迟初始化。这是我实现的第一步:
public class ExampleClass {
private static final Map<String, String> CACHED_STRINGS = new HashMap<String, String>();
public String getText(String key) {
String string = CACHED_STRINGS.get(key);
if (string == null) {
synchronized (CACHED_STRINGS) {
string = CACHED_STRINGS.get(key);
if (string == null) {
string = createString();
CACHED_STRINGS.put(key, string);
}
}
}
return string;
}
}
Run Code Online (Sandbox Code Playgroud)
编写完这段代码后,Netbeans就“双重检查锁定”警告了我,因此我开始对其进行研究。我找到了“双重检查锁定已损坏”声明并已阅读,但我不确定我的实现是否会受到它提到的问题的影响。看来本文中提到的所有问题都与new在synchronized块中使用运算符进行对象实例化有关。我没有使用new运算符,并且字符串是不可变的,因此我不确定本文是否与这种情况相关。这是在字符串中缓存字符串的线程安全方法HashMap吗?线程安全性是否取决于createString()方法中采取的措施?
即使经过这个,我仍然不清楚最终的使用如何导致安全发布在下面的代码中.有人能给出一个易于理解的解释.
public class SafeListener
{
private final EventListener listener;
private SafeListener()
{
listener = new EventListener()
{ public void onEvent(Event e)
{ doSomething(e); }
};
}
public static SafeListener newInstance(EventSource source)
{
SafeListener safe = new SafeListener();
source.registerListener(safe.listener);
return safe;
}
}
Run Code Online (Sandbox Code Playgroud) 当我阅读 Brian Goetz 的《Java 并发实践》时,我记得他在有关可见性的章节中说过“另一方面,即使不使用同步来发布对象引用,也可以安全地访问不可变对象”。
我认为这意味着,如果您发布一个不可变的对象,则所有字段(包括可变的最终引用)对于可能使用它们的其他线程都是可见的,并且至少是该对象完成构造时的最新状态。
现在,我在https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html中读到“现在,说了所有这些,如果在线程构造一个不可变对象之后(即,仅包含最终字段的对象),如果您想确保所有其他线程都能正确看到它,那么通常仍然需要使用同步。没有其他方法可以确保,例如,第二个线程将看到对不可变对象的引用。程序从最终字段获得的保证应该通过深入而仔细地理解代码中如何管理并发性来仔细调整。
他们似乎互相矛盾,我不知道该相信哪一个。
我还读到,如果所有字段都是最终字段,那么即使对象本身不是不可变的,我们也可以确保安全发布。例如,由于这个保证,在发布此类的对象时,我一直认为实践中 Brian Goetz 的并发中的这段代码是没问题的。
@ThreadSafe
public class MonitorVehicleTracker {
@GuardedBy("this")
private final Map<String, MutablePoint> locations;
public MonitorVehicleTracker(
Map<String, MutablePoint> locations) {
this.locations = deepCopy(locations);
}
public synchronized Map<String, MutablePoint> getLocations() {
return deepCopy(locations);
}
public synchronized MutablePoint getLocation(String id) {
MutablePoint loc = locations.get(id);
return loc == null ? null : new MutablePoint(loc);
}
public synchronized void setLocation(String id, int x, int y) {
MutablePoint loc = locations.get(id);
if (loc …Run Code Online (Sandbox Code Playgroud) concurrency multithreading visibility immutability thread-safety