#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
, или что-нибудь еще, что вам нравится: изменение поля без установления предшествующих отношений с кодом, который его читает, нарушается, и вы делаете именно это.
Некоторые методы могут указывать, что они потокобезопасны. Как правило, пытаться обмениваться данными между потоками значительно сложнее, чем просто вызывать кучу этих методов и молиться.