Java LocalTime обеспечивает потокобезопасность

#java #java-time

#java #java-время

Вопрос:

В документации LocalTime говорится, что он потокобезопасен. Я понимаю, что это само по себе потокобезопасно. Но было бы ли это потокобезопасно, если бы я поделился им между многими потоками, подобными этому?

 public class Timesheet {

private static boolean run = true;

private static LocalTime activity;

public static void main(String[] args) {

    CompletableFuture.runAsync(() -> {
        activity =  LocalTime.now();
    }

    CompletableFuture.runAsync(() -> {
        activity =  LocalTime.now();
    }

    try {
        while (run) {
           Thread.sleep(12000);
           run = false; 
        }
    } catch (InterruptedException e) {
        
    } finally {
        //print activity
    }
}
  

Я пытаюсь получить точное время. Если бы я проверял время активности в основном потоке. будет ли это точно?

Редактировать:

Теперь я понимаю, почему мой код не является потокобезопасным. Если бы я манипулировал экземпляром LocalTime внутри синхронизированного кода, сделало бы это мой код потокобезопасным?

 CompletableFuture.runAsync(() -> {
    synchronized (activity) {
        activity = LocalTime.now();
    }
}       
  

Комментарии:

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

2. Не могли бы вы, пожалуйста, дать мне подсказку, что я могу сделать, чтобы сделать мою программу потокобезопасной? Я думал, что синхронизации activity экземпляра достаточно, независимо от того, сколько раз ссылка на адрес памяти, на которую он ссылается, изменяется. @LouisWasserman. Я не могу понять этот ваш намек «Вы должны синхронизировать что-то, что остается фиксированным».

3. Я рассуждаю так: не имеет значения, к какому потоку обращается activity , этот поток будет заблокирован activity (поэтому другие потоки не могут обновить его значение, и им приходится ждать), назначьте ему новое LocalTime и продолжайте. Для меня activity это исправлено.

4. Если бы моя логика была правильной, то activity всегда будет печатать точное время.

5. Это synchronized (something) { ... } правильно, но значение activity меняется, так что это нехорошо something .

Ответ №1:

LocalDate это не просто потокобезопасность.

Он неизменяем.

Потокобезопасность, в терминах типа, относится к понятию того, что происходит, когда вы изменяете объект — вы делаете это всегда через точку: someExprThatRefersToThatObject.field = foo или someExprThatRefersToThatObject.method() где этот метод приведет к тому, что объект будет каким-то образом изменен.

Ничто из этого не возможно с LocalDate. Нет методов, которые изменяют вещи, и нет полей, которые вы могли бы изменить. Вместо этого LocalDate имеет методы, которые вообще не изменяют объект; вместо этого они возвращают новые. Например, someDate.plusDays(1) вообще не меняется someDate . Вместо этого он просто возвращает новый LocalDate объект.

Это означает, что ВАШИ ссылки меняются, если вы пишете подобный код activity = LocalTime.now(); , и потокобезопасность этого имеет прямое отношение к LocalTime, все это связано с вами.

В частности, в вашем примере это не является потокобезопасным. Не имеет значения, что это за тип activity . Это может быть int , String , LocalTime , ArrayList , или что-нибудь еще, что вам нравится: изменение поля без установления предшествующих отношений с кодом, который его читает, нарушается, и вы делаете именно это.

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