Если это не является потокобезопасным, каким образом я могу сделать его безопасным для потоков? - PullRequest
0 голосов
/ 01 февраля 2019

Что касается HTTPSession, я использую Java-сервлеты, а не фреймворк.Я читал об AtomicReferences, но не ясно, как я могу использовать это, чтобы сделать этот поток кода безопасным.Правильно ли я полагаю, что могу просто пометить updateSessionHashSet синхронизированным для обеспечения безопасности?Я понимаю, что это не рекомендуется из-за неэффективности.Какие еще параметры и синтаксис есть?

Внутри HTTPServlet:

private void updateSessionHashSet(HttpServletRequest req){
  HashSet<String> hs = req.getSession().getAttribute("theHashSet");
  String csv = req.getParameter("theCsv");

  String[] arr = csv.split(",");
  for(int i = 0; i < arr.length; i++){
      hs.add(arr[i].trim());
  }
}

public void doPost(HttpServletRequest  req,HttpServletResponse res) throws IOException {
   updateSessionHashSet(req);
}

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Посты, на которые вы ссылаетесь, сообщают вам, что HTTPSession является общим состоянием, и вы должны быть осторожны, когда несколько потоков могут изменить его.Здесь существует возможность вмешательства потоков, если у вас есть два одновременных запроса POST от одного и того же пользователя, которые вызывают этот метод.Вы можете обработать это чем-то вроде

private void updateSessionHashSet(HttpServletRequest req){
    String csv = req.getParameter("theCsv");
    Set<String> hs = new HashSet<String>();
    String[] arr = csv.split(",");
    for(int i = 0; i < arr.length; i++){
        hs.add(arr[i].trim());
    }
    req.getSession().setAttribute("theHashSet", hs);
}

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

В качестве альтернативы вам могут понравиться некоторыеиз ответов на связанные посты советуют и синхронизируют объект HttpSession, но поскольку вы синхронизируете объект Java, который является локальным для данного экземпляра приложения, вы должны обратить внимание на случай, когда приложение распределено по несколькимузлы.Синхронизация означает использование общей блокировки, и для всех JVM нет общего доступа.

Обычно ИТ-отделы хотят развернуть приложение в нескольких экземплярах, чтобы избежать единой точки отказа.Вы можете справиться с проблемой синхронизации, прикрепив сеанс к определенному серверу, но это затрудняет балансировку нагрузки.

Кстати, хранение вещей в HttpSession, вероятно, не лучший план, вы должны сохранить этов каком-то хранилище данных.Лучший способ обеспечить безопасный параллелизм - минимизировать количество изменяемого состояния.HttpSession не является чем-то, что можно использовать в качестве долговременного хранилища.

Для рекомендаций по безопасности потоков Java EE у меня есть соответствующий ответ здесь .

0 голосов
/ 01 февраля 2019

Вам следует заботиться о безопасности потоков, когда в вашем классе есть разделяемые изменяемые члены.

Локальные переменные хранятся в собственном стеке каждого потока, поэтому локальные переменные никогда не разделяются между потоками.То же самое относится к локальным примитивным переменным.

Случай 1, локальный потокобезопасный примитив:

class Processor {
    public void threadSafeMethod() {
         int count = 0;
         count++;
    }
}

Локальные ссылки на объекты более сложны.Сама ссылка не является общей.Однако объект, на который есть ссылки, хранится в общей куче.

Если объект, созданный локально, никогда не выходит за пределы метода, он является потокобезопасным.

Случай 2, локальная ссылка на потокобезопасность:

class Processor {
    public void threadSafeMethod() {
         StringBuilder sb = new StringBuilder("Text");
         appendPoint(sb);
    }

    public void appendPoint(StringBuilder b) {
         b.append(". ");
    }
}

Case 3, не поддерживающий потоки разделяемый изменяемый члены:

class Processor {

    private StringBuilder sb; // shared mutable reference

    public void nonThreadSafeMethod() {
         sb = new StringBuilder("Text");
         appendPoint(sb);
    }

    public void appendPoint(StringBuilder b) {
         b.append(". ");
    }
}

Case 4, защищенный от потоков разделяемый неизменяемый члены :

class Processor {
    private String s; // shared immutable reference

    public void threadSafeMethod(final String str) {
         s = str; // Thread-safe because immutable
    }
}
...