Я написал простой демонстрационный код, чтобы проверить, «как работает Daemon Thread». Но демонстрация демонстрирует другое странное поведение: я делаю Deque
для хранения элемента с именем Event и разделяю его на два рабочих потока, один добавляю элемент в Deque. еще раз проверьте размер Deque и удалите элемент, который создается за 3 секунды a go. Здесь произошло странное: вызов size()
Deque всегда возвращает 0. Я знаю, что ArrayDeque
и LinkedDeque
не являются поточно-ориентированными, но я могу исправить эту странную вещь следующим образом: 1 、 Измените инструменты Deque на ConcurrentLinkedDeque. 2 、 синхронизировал экземпляр двухсторонней очереди. 3. Перед запуском Cleaner поместите элемент в общую двухстороннюю очередь. 4 、 проверьте размер и распечатайте его. Все это работает хорошо, это очень странно, и я не знаю почему.
Вот демонстрационный код и моя среда выполнения:
java версия "1.8.0_141 «Java (TM) Среда выполнения SE (сборка 1.8.0_141-b15) Java 64-разрядная серверная виртуальная машина HotSpot (TM) (сборка 25.141-b15, смешанный режим)
MacBook Pro (13 дюймов, 2016 г., два порта Thunderbolt 3) MacOS Catalina 10.15.6
public class CleanerTask extends Thread {
private transient Deque<Event> deque;
private AtomicInteger doRemoveTimes = new AtomicInteger(0);
public AtomicInteger getDoRemoveTimes() {
return doRemoveTimes;
}
public CleanerTask(Deque<Event> deque) {
this.deque = deque;
setDaemon(true);
}
@Override
public void run() {
//System.out.println("Cleaner: watch deque " + deque);
while (true) {
clean();
}
}
private void clean() {
//fix 2
/*synchronized (deque) {
if(deque.size() == 0) {
return;
}
}*/
if (deque.size() == 0) {
//System.out.println("Cleaner: deque's size:" + deque.size());//fix 3
return;
}
int removes = 0;
int beforeNext;
do {
beforeNext = removes;
Event event = deque.getLast();
if (Duration.between(event.getTime(), LocalTime.now()).getSeconds() > 3) {
deque.removeLast();
System.out.println(event + " is removed");
removes++;
}
} while (removes > beforeNext && deque.size() > 0);
if (removes > 0) {
doRemoveTimes.addAndGet(removes);
System.out.printf("Cleaner: cleaned %d, remained %d\n", removes, deque.size());
}
}
}
public class WriterTask implements Runnable {
private Deque<Event> deque;
public WriterTask(Deque<Event> deque) {
this.deque = deque;
}
@Override
public void run() {
System.out.println(LocalTime.now() + "-" + Thread.currentThread().getId() + ": start write event to the deque: " + deque);
for(int i = 0; i < 10; i++) {
Event event = new Event("event generated by " + Thread.currentThread().getId());
deque.addFirst(event);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(LocalTime.now() + "-" + Thread.currentThread().getId() + ": finished");
}
}
public class DaemonCleanMain {
public static void main(String[] args) {
//Deque<Event> deque = new ConcurrentLinkedDeque<>();//fix 1
Deque<Event> deque = new ArrayDeque<>();
WriterTask writer = new WriterTask(deque);
int i = args.length > 0 ? Integer.parseInt(args[0]) : 1;
while (i > 0) {
Thread thread = new Thread(writer);
thread.start();
i--;
}
//fix 4
/* try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
CleanerTask cleaner = new CleanerTask(deque);
cleaner.start();
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("size of deque: " + deque.size());
System.out.println("Cleaner is work? " + cleaner.getDoRemoveTimes());
}
}
}
public class Event {
public Event(String name) {
this.name = name;
this.time = LocalTime.now();
}
public Event(String name, LocalTime time) {
this.name = name;
this.time = time;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalTime getTime() {
return time;
}
public void setTime(LocalTime time) {
this.time = time;
}
private String name;
private LocalTime time;
@Override
public String toString() {
return "Event{" +
"name='" + name + '\'' +
", time=" + time +
'}';
}
}
Вопрос: исправление 3 и 4 , меня очень удивляет, потому что я считаю это очень странным методом исправления. И, хотя ArrayDeque не является потокобезопасным, но когда Writer остановлен, Cleaner по-прежнему получает size () return 0, когда на самом деле сейчас выполняется только один поток (кроме основного), он работает как двухсторонний к Очистителю является окончательным и неизменным.