Как безопасно установить / получить строку в Java? - PullRequest
2 голосов
/ 13 ноября 2011

Я прочитал, что класс 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).

Ответы [ 3 ]

2 голосов
/ 13 ноября 2011

Создание aString volatile - это все, что вам нужно в этом случае (т. Е. Чтение после записи всегда будет видеть новейшее значение) - синхронизация метода не особенно полезна, поскольку мы выполняем только один оператор - в в обоих случаях, так что вам все равно потребуется синхронизация более высокого уровня, если вы хотите выполнять больше работы (скажем, «Если String - это XYZ, тогда назначьте ему XYA»). То есть синхронизированные и изменчивые дают вам одинаковые гарантии (кроме очевидной разницы, если мы используем синхронизированные в других местах класса)

Так что volatile достаточно и более производительно, но синхронизация так же хороша - единственное различие в производительности, которое вы могли заметить, было, если у вас было много разрешенных обращений, но в остальном это не имеет значения - синхронизированный чрезвычайно оптимизирован для неконтролируемых обращений по крайней мере на Hotspot (но я предполагаю, что то же самое верно для всех современных JVM).

2 голосов
/ 13 ноября 2011

Вопрос 1: Это зависит от того, что вы подразумеваете под потокобезопасным, Эрик Липперт написал очень хороший пост в блоге об этом здесь ... Но объявление aString как volatile будет означать, что любое чтение в разных потоках гарантированочтобы быть правильным.

Вопрос 2:

Используйте конструкцию try ... finally, разблокируя ее в блоке finally, например:

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

public void setString(s) {
  try {        
    aLock.lock();
    aString = s;
  } finally {
    aLock.unlock();
  }
}
1 голос
/ 13 ноября 2011

Использовать синхронизированное ключевое слово:

   public synchronized String getString() {
        return aString;
    }

    public synchronized void setString(s) {
        aString = s;
    }
...