2

我读过 Java String 类是不可变的和线程安全的,但我仍然对字符串的引用分配是否是线程安全的感到困惑。

第一个问题:如果线程 A 调用Foo.setString()而线程 B 调用Foo.getString(),那么下面的代码是线程安全的吗?

Class Foo {
    String aString;
    public String getString() {
        return aString;
    }
    public void setString(s) {
        aString = s;
    }
}

第二个问题:如果上面的代码不是线程安全的,使用了ReentrantLock,Foo.getString()方法怎么写?

Class Foo {
    String aString;
    ReentrantLock aLock;
    public String getString() {
        aLock.lock();
        return aString;
        aLock.unlock(); // This line will be unreachable. How to fix??
    }
    public void setString(s) {
        aLock.lock();
        aString = s;
        aLock.unlock();
    }
}

我必须使用 ReentrantLock 因为我需要使用 tryLock(timeout) 功能。

4

3 回答 3

2

Question 1: It depends what you mean by thread safe, Eric Lippert wrote a very good blog post about it here... But declaring aString as volatile will mean that any reads on different threads are guaranteed to be correct.

Question 2:

Use a try... finally construct, unlocking in the finally block eg:

public String getString() {
  try {        
    aLock.lock();
    return aString;
  } finally {
    aLock.unlock();
  }
}

public void setString(s) {
  try {        
    aLock.lock();
    aString = s;
  } finally {
    aLock.unlock();
  }
}
于 2011-11-13T18:00:21.060 回答
2

在这种情况下,您只需要设置 volatile (即在写入后读取始终会看到最新值) -使aString方法同步并不是特别有用,因为我们只执行一条语句 - 在这两种情况下,你都会如果你想做更多的工作,无论如何都需要更高级别的同步(比如“如果字符串是 XYZ,那么将 XYA 分配给它”)。即 synchronized 和 volatile 都为您提供相同的保证(如果我们在类中的其他地方使用 synchronized 会产生明显的差异)

所以 volatile 就足够了,而且性能更高,但是 synchronized 也一样好 - 你可以注意到的唯一性能差异是如果你有很多竞争访问,但否则没关系 - synchronized 至少针对非竞争访问进行了极大优化热点(但我认为所有现代 JVM 都是如此)。

于 2011-11-13T18:11:48.877 回答
1

Use synchronized keyword :

   public synchronized String getString() {
        return aString;
    }

    public synchronized void setString(s) {
        aString = s;
    }
于 2011-11-13T18:00:22.340 回答