В Java есть специальный поток — поток-демон, который имеет очень низкий приоритет и будет выполняться только тогда, когда другие потоки в той же программе не выполняются.
Поскольку потоки-демоны обладают этими характеристиками, они обычно используются для предоставления услуг обычным потокам (также называемым пользовательскими потоками) в программе. Обычно они имеют бесконечный цикл или используются для ожидания запросов служб, выполнения задач и т. д. Они не могут выполнять никакой важной работы, поскольку мы не уверены, когда им будет выделено процессорное время, и они автоматически завершат свою работу, когда другие потоки не выполняются. Типичным применением потока этого типа является сбор мусора Java.
В примере в этом разделе мы создадим два потока: один — обычный поток, который записывает события в очередь; другой — поток-демон, который очищает события в очереди и удаляет события, существующие более 10 секунд.
знай это
Выполните следующие шаги, чтобы реализовать пример программы.
1. Создайте класс Event, который будет использоваться только для сохранения информации о событиях, необходимой для выполнения программы. Объявите два свойства: одно — свойство даты типа java.util.Date, а другое — свойство события типа String, затем сгенерируйте методы чтения и записи для этих двух свойств. Код выглядит следующим образом:
Скопируйте код кода следующим образом:
событие общественного класса {
личная дата; дата;
частное событие String;
публичная дата getDate() {
дата возвращения;
}
public void setDate(Дата дата) {
this.date = дата;
}
публичная строка getEvent() {
возвратное событие;
}
public void setEvent (String event) {
это.событие = событие;
}
}
2. Создайте класс WriterTask и реализуйте интерфейс Runnable. Код выглядит следующим образом:
Скопируйте код кода следующим образом:
публичный класс WriterTask реализует Runnable {
3. Объявите атрибут очереди, используемый для хранения событий, реализуйте конструктор класса и используйте его параметры для инициализации атрибута очереди. Код выглядит следующим образом:
Скопируйте код кода следующим образом:
частная очередь Deque<Event>;
public WriterTask(Deque<Event> deque) {
this.deque = дек;
}
4. Реализуйте метод run() этой задачи, который содержит цикл, который проходит 100 раз. При каждом обходе создается новый объект Event, затем сохраняется в очереди и приостанавливается на 1 секунду. Код выглядит следующим образом:
Скопируйте код кода следующим образом:
@Override
общественный недействительный запуск () {
для (int я = 0; я <100; я++) {
Событие событие = новое событие();
event.setDate(новая дата());
event.setEvent(String.format("Поток %s сгенерировал событие",
Thread.currentThread().getId()));
deque.addFirst(событие);
пытаться {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
е.printStackTrace();
}
}
}
5. Создайте класс с именем CleanerTask и унаследуйте класс Thread. Код выглядит следующим образом:
Скопируйте код кода следующим образом:
общественный класс CleanerTask расширяет поток {
6. Объявите атрибут очереди, используемый для хранения событий, реализуйте конструктор класса и используйте его параметры для инициализации атрибута очереди. В методе создания установите поток как поток демона, вызвав метод setDaemon(). Код выглядит следующим образом:
Скопируйте код кода следующим образом:
частная очередь Deque<Event>;
public CleanerTask(Deque<Event> deque) {
this.deque = дек;
setDaemon (истина);
}
7. Реализуйте метод run() В теле метода имеется бесконечный цикл для получения текущего времени и последующего вызова методаclen(). Код выглядит следующим образом:
Скопируйте код кода следующим образом:
@Override
общественный недействительный запуск () {
в то время как (истина) {
Дата дата = новая дата();
очистить (дата);
}
}
8. Реализуйте метод clean(). В этом методе получите последнее время, а затем проверьте разницу во времени между временем и текущим временем. Если оно было создано 10 секунд назад, удалите текущее событие, а затем проверьте следующее. событие. Если событие удалено, информация об удаленном событии будет распечатана, а также будет распечатана последняя длина очереди, чтобы можно было наблюдать за ходом выполнения программы. Код выглядит следующим образом:
Скопируйте код кода следующим образом:
Private void clean(Дата дата) {
большая разница;
логическое удаление;
если (deque.size() == 0) {
возвращаться;
}
удалить = ложь;
делать {
Событие e = deque.getLast();
разница = date.getTime() - e.getDate().getTime();
если (разница > 10000) {
System.out.printf("Очиститель: %s/n", e.getDate());
deque.removeLast();
удалить = правда;
}
} Пока (разница > 10000);
если (удалить) {
System.out.printf("Очиститель: Размер очереди: %d/n", deque.size());
}
}
9. Создайте основной класс программы — класс Main, а затем реализуйте метод main(). Код выглядит следующим образом:
Скопируйте код кода следующим образом:
общественный класс Main {
public static void main(String[] args) {
10. Используйте класс Deque, чтобы создать очередь для хранения событий. Код выглядит следующим образом:
Скопируйте код кода следующим образом:
Deque<Event> deque = новый ArrayDeque<>();
11. Создайте и запустите три потока WriterTask и один поток CleanerTask. Код выглядит следующим образом:
Скопируйте код кода следующим образом:
Deque<Event> deque = новый ArrayDeque<>();
WriterTask писатель = новый WriterTask (дек);
для (int я = 0; я <3; я++) {
Поток потока = новый поток (писатель);
поток.start();
}
Очиститель CleanerTask = новый CleanerTask(deque);
очиститель.start();
12. Запустите программу и просмотрите результаты выполнения.
знаю почему
Анализируя результаты выполнения программы, мы видим, что очередь сначала увеличивается до 30, а затем меняется между 27 и 30, пока выполнение программы не закончится.
Программа сначала начинает выполнение из трех потоков WriterTask. Каждый поток сначала добавляет событие в очередь, а затем приостанавливает работу на 1 секунду. По прошествии первых 10 секунд в очереди будет тридцать событий. В течение этих 10 секунд, когда все три потока WriterTask спят, поток CleanerTask также будет запущен, но никакие события не будут удалены, поскольку время генерации всех событий не превышает 10 секунд. По истечении первых 10 секунд три WriterTask добавляют в очередь три события каждую секунду, аналогично CleanerTask удаляет три события каждую секунду; Таким образом, количество событий колеблется между 27 и 30.
Когда все потоки WriterTask спят, мы можем свободно обрабатывать время, позволяя потоку демона работать в это время. Если вы установите более короткое время сна потока WriterTask, поток CleanerTask будет получать меньше времени работы ЦП. В этом случае длина очереди будет продолжать расти, поскольку поток CleanerTask никогда не получает достаточно времени для удаления достаточного количества событий.
бесконечный
Поток можно установить как поток демона, только вызвав метод setDaemon() перед вызовом метода start(). После запуска потока состояние демона невозможно изменить.
Вы также можете использовать isDaemon(), чтобы проверить, является ли поток потоком демона. Если это поток демона, он возвращает true; если это обычный поток, он возвращает false;
Используйте доктрину
Эта статья переведена из «Книги по параллелизму Java 7» (Д Гуа Ге украл ее как «Коллекция примеров параллелизма Java7») и используется только в качестве учебных материалов. Его нельзя использовать в коммерческих целях без разрешения.
Небольшой успех
Полные версии всех примеров кода, используемых в этом разделе.
Полный код класса Event
Скопируйте код кода следующим образом:
пакет com.diguage.books.concurrencycookbook.chapter1.recipe7;
импортировать java.util.Date;
/**
*Класс информации о мероприятии
* Дата: 19 сентября 2013 г.
* Время: 22:56
*/
событие общественного класса {
личная дата; дата;
частное событие String;
публичная дата getDate() {
дата возвращения;
}
public void setDate(Дата дата) {
this.date = дата;
}
публичная строка getEvent() {
возвратное событие;
}
public void setEvent (String event) {
это.событие = событие;
}
}
Полный код класса WriterTask
Скопируйте код кода следующим образом:
пакет com.diguage.books.concurrencycookbook.chapter1.recipe7;
импортировать java.util.Date;
импортировать java.util.Deque;
импортировать java.util.concurrent.TimeUnit;
/**
* Генерировать событие каждую секунду.
* Дата: 19 сентября 2013 г.
* Время: 22:59
*/
публичный класс WriterTask реализует Runnable {
частная очередь Deque<Event>;
public WriterTask(Deque<Event> deque) {
this.deque = дек;
}
@Override
общественный недействительный запуск () {
для (int я = 0; я <100; я++) {
Событие событие = новое событие();
event.setDate(новая дата());
event.setEvent(String.format("Поток %s сгенерировал событие",
Thread.currentThread().getId()));
deque.addFirst(событие);
пытаться {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
е.printStackTrace();
}
}
}
}
Полный код класса CleanerTask
Скопируйте код кода следующим образом:
пакет com.diguage.books.concurrencycookbook.chapter1.recipe7;
импортировать java.util.Date;
импортировать java.util.Deque;
/**
* Уборка мероприятий
* Дата: 19 сентября 2013 г.
* Время: 23:33
*/
общественный класс CleanerTask расширяет поток {
частная очередь Deque<Event>;
public CleanerTask(Deque<Event> deque) {
this.deque = дек;
setDaemon (истина);
}
@Override
общественный недействительный запуск () {
в то время как (истина) {
Дата дата = новая дата();
очистить (дата);
}
}
/**
* Удалить событие.
*
* @param дата
*/
Private void clean(Дата дата) {
большая разница;
логическое удаление;
если (deque.size() == 0) {
возвращаться;
}
удалить = ложь;
делать {
Событие e = deque.getLast();
разница = date.getTime() - e.getDate().getTime();
если (разница > 10000) {
System.out.printf("Очиститель: %s/n", e.getDate());
deque.removeLast();
удалить = правда;
}
} Пока (разница > 10000);
если (удалить) {
System.out.printf("Очиститель: Размер очереди: %d/n", deque.size());
}
}
}
Полный код основного класса
Скопируйте код кода следующим образом:
пакет com.diguage.books.concurrencycookbook.chapter1.recipe7;
импортировать java.util.ArrayDeque;
импортировать java.util.Deque;
/**
* Дата: 19 сентября 2013 г.
* Время: 23:54
*/
общественный класс Main {
public static void main(String[] args) {
Deque<Event> deque = новый ArrayDeque<>();
WriterTask писатель = новый WriterTask (дек);
для (int я = 0; я <3; я++) {
Поток потока = новый поток (писатель);
поток.start();
}
Очиститель CleanerTask = новый CleanerTask(deque);
очиститель.start();
}
}