Безопасность потока на блоке кода, который имеет внешнюю ссылку - PullRequest
1 голос
/ 10 мая 2019

У меня есть вопрос относительно безопасности потоков.Приведенный ниже код, который находится внутри блока синхронизации, имеет внешний вызов метода (httpClient.execute ()) для ссылки на переменную класса текущего объекта.Этот внешний вызов вызывает проблему безопасности потока?Если да, как решить эту проблему?

public class KeyClient {

    private final HttpClient httpClient;

    public getKey() {
        synchronized (this) {
            if (Paths.get("fileName").toFile().exists()) {
                if (file == null) {
                    file = new File("fileName");
                }
            } else {
                HttpResponse response = httpClient.execute();
                Map map = mapper.readValue(response.getResponseBody(), Map.class);
                file = new File("fileName");
                mapper.writeValue(file, map);
            }
        }
    }
}

public class HttpClient {

    public HttpResponse execute() {
        //Some code
        return new HttpResponse(200, "");
    }
}

Ответы [ 5 ]

3 голосов
/ 10 мая 2019

Нет, не будет.

Если вы вызываете синхронизированный блок , то все, что находится внутри блока, также блокируется. Блокировка включается, когда вы входите в синхронизированный блок иотключается при выходе из этого блока.

Однако вызовы выполнения метода другими потоками не блокируются - каждый может вызвать их одновременно.

0 голосов
/ 10 мая 2019

Оператор synchronized (this) гарантирует, что никакой другой поток не войдет в последующий блок, пока один поток уже ввел его. С этой точки зрения код является потокобезопасным.

Однако ничто не защищает httpClient от использования другим не синхронизированным методом в классе KeyClient, который вызывается из другого потока.

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

0 голосов
/ 10 мая 2019

У вас есть два возможных общих ресурса, на которые вы должны обратить внимание.Они оба могут поставить под угрозу безопасность потоков.

  • Экземпляр HttpClient внутри KeyClient: даже если он помечен как final, KeyClient должен отвечать за создание HttpClient в конструкторе .Вы не должны делиться экземпляром HttpClient с любым другим классом.Кроме того, рекомендуется проверить безопасность потоков для каждого метода каждого класса, которым вы делитесь, в их JavaDoc.

  • Файл с "fileName" также должен быть Рассматривайте как общий ресурс, поэтому имейте в виду, что другой поток может записывать в тот же файл одновременно, что испортит ваши данные.Убедитесь, что каждый поток записывает в свой файл одновременно.Хороший подход заключается в создании уникального префикса имени файла на лету, когда файл записывается.Например, это может быть thread-ID-process-ID-timestamp-fileName.txt

0 голосов
/ 10 мая 2019

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

Таким образом, код безопасен для потоков.

0 голосов
/ 10 мая 2019

HTTPClient равно final, что означает, что это постоянная переменная, и ее нельзя изменить после инициализации.Следовательно, этот код, скорее всего, не имеет проблем с безопасностью потоков (если, конечно, внутри класса HTTPClient нет изменяемых переменных, которые не синхронизированы).

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