Безопасность потоков в Java - PullRequest
1 голос
/ 08 октября 2010

Все,

Я начал изучать потоки Java в последние несколько дней и читал только о сценариях, в которых даже после использования методов / блоков синхронизатора код / ​​класс остается уязвимым для проблем параллелизма.Может ли кто-нибудь представить сценарий, когда синхронизированные блоки / методы не работают?И какой должна быть альтернатива в этих случаях для обеспечения безопасности потока.

Ответы [ 5 ]

3 голосов
/ 08 октября 2010

Правильное поведение при одновременном доступе - сложная тема, и она не так проста, как простое наложение synchronized на все, так как теперь вам нужно подумать о том, как операции могут чередоваться.

Например, представьте, что выиметь класс как список, и вы хотите сделать его потокобезопасным.Таким образом, вы делаете все методы синхронизированными и продолжаете.Скорее всего, клиенты могут использовать ваш список следующим образом:

int index = ...; // this gets set somewhere, maybe passed in as an argument

// Check that the list has enough elements for this call to make sense
if (list.size() > index)
{
    return list.get(index);
}
else
{
    return DEFAULT_VALUE;
}

В однопоточной среде этот код совершенно безопасен.Однако, если к списку обращаются (и, возможно, изменяют) одновременно, размер списка может измениться после вызова size(), но до вызова get().Таким образом, список может «невозможно» вызвать исключение IndexOutOfBoundsException (или подобное) в этом случае, даже если размер был проверен заранее.

Нет быстрого способа исправить это - вам просто нужно тщательно подумать об использовании- случаи для вашего класса / интерфейса и убедитесь, что вы действительно можете гарантировать их при чередовании с любыми другими действительными операциями.Часто для этого может потребоваться дополнительная сложность или просто больше деталей в документации.Если класс гипотетического списка указывает, что он всегда синхронизируется на своем собственном мониторе, тогда эту специфическую ситуацию можно исправить как

synchronized(list)
{
    if (list.size() > index)
    {
        return list.get(index);
    }
}

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

1 голос
/ 08 октября 2010

Очень хорошие статьи о параллелизме и модели памяти Java можно найти на сайте Angelika Langers

1 голос
/ 08 октября 2010

Сценарий 1 Классический тупик:

Object Mutex1;
Object Mutex2;


public void method1(){
    synchronized(Mutex1){
        synchronized(Mutex2){
        }
    }
}

public void method2(){
    synchronized(Mutex2){
        synchronized(Mutex1){
        }
    }
}

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

0 голосов
/ 08 октября 2010

Синхронизированные методы не позволяют другим методам / блокам, требующим того же монитора, запускаться при их выполнении. Но если у вас есть 2 метода, скажем, int get () и set (int val) и есть метод где-то еще, который делает obj.set (1 + obj.get ());

и этот метод выполняется в два потока, вы можете закончить с увеличением значения на один или два, в зависимости от непредсказуемых факторов.

Поэтому вы должны каким-то образом защищать, используя такие методы (но только если это необходимо).

кстати. используйте каждый монитор для как можно меньшего количества функций / блоков, поэтому синхронизируются только те, кто может ошибочно влиять друг на друга.

И постарайтесь раскрыть как можно меньше методов, требующих дополнительной защиты.

0 голосов
/ 08 октября 2010

«уязвимы для проблем параллелизма» очень расплывчато. Это поможет узнать, что вы на самом деле читали и где. Две вещи, которые приходят на ум:

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