Где я не Threadsafe? - PullRequest
       4

Где я не Threadsafe?

2 голосов
/ 18 января 2012

Я использую объект, который служит примерно как обертка для карты строк:

public class Wrapper {
  private Map<String, String> values;
  private Formatter formatter;

  public BigDecimal getSpecialValue() {
    String result = values.get("Special");
    return formatter.formatNumber(result);
  }
}

Вышеупомянутый форматер служит примерно как средство отображения для SimpleDateFormat

 public class Formatter {
   private static final NumberFormat NUMBER_FORMAT;

   public BigDecimal formatNumber(String s) {
     Number num = NUMBER_FORMAT.parse(s);
     if (num instanceof Integer) {
       return new BigDecimal((Integer) num);
     } else if (num instanceof Double) {
       return new BigDecimal((Double) num);
     } ...
   }
 }

Когда я обращаюсь к методу getSpecialValue() сразу несколькими потоками, возникает некоторое поведение, которое может быть объяснено только одновременным доступом, например, может быть NumberFormatException или ParseException, где анализируемая строка равна .430.430вместо .430 и т. д.

Меня интересуют два аспекта: 1.) Оболочка доступна только для чтения.Хотя доступ к коллекции не синхронизирован, у меня сложилось впечатление, что это всегда должно работать.2.) В одной из первых попыток найти проблему я изменил конструктор класса Wrapper, чтобы он выполнял метод formatNumber (очевидно, однопоточный), что исключало все исключения во время выполнения.

Кто-нибудь может объяснить?

Редактировать: Карта в классе Wrapper заполнена конструктором, что наиболее определенно происходит однопоточным.После этого оболочка создается так, что карта является неизменной.

Ответы [ 2 ]

9 голосов
/ 18 января 2012

Просто поиск в jdoc для "thread" нашел бы вам следующее для класса NumberFormat: Number formats are generally not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

1 голос
/ 18 января 2012
  1. NumberFormat не является потокобезопасным. Поэтому хранение его в статической переменной и использование его из нескольких потоков приведет к проблемам. Либо синхронизируйте каждое использование этого объекта, либо сохраните его в переменной ThreadLocal.

  2. Даже если доступ к оболочке возможен только для чтения, должно быть какое-то время, когда карта значений инициализируется и заполняется, и где создается форматтер, иначе форматировать ничего не будет. Вы не показали настоящий, полный код класса, поэтому у вас могут быть как минимум проблемы с видимостью и в этом классе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...