Java has a special thread, the daemon thread, which has a very low priority and will only be executed when other threads in the same program are not executing.
Because daemon threads have these characteristics, they are generally used to provide services for ordinary threads (also called user threads) in the program. They generally have an infinite loop, or are used to wait for request services, or to perform tasks, etc. They cannot do any important work because we are not sure when they will be allocated CPU time, and they will automatically terminate when no other threads are executing. A typical application of this type of thread is Java garbage collection.
In the example in this section, we will create two threads, one is a normal thread, which writes events to the queue; the other is a daemon thread, which clears events in the queue and deletes events that exist for more than 10 seconds.
know it
Follow the steps below to implement the sample program.
1. Create an Event class, which is only used to save event information required for program execution. Declare two properties, one is the date property of the java.util.Date type, and the other is the event property of the String type; then generate the read and write methods for these two properties. The code is as follows:
Copy the code code as follows:
public class Event {
private Date date;
private String event;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getEvent() {
return event;
}
public void setEvent(String event) {
this.event = event;
}
}
2. Create a class named WriterTask and implement the Runnable interface. The code is as follows:
Copy the code code as follows:
public class WriterTask implements Runnable {
3. Declare a queue attribute used to store events, implement the constructor of the class, and use its parameters to initialize the queue attribute. The code is as follows:
Copy the code code as follows:
private Deque<Event> deque;
public WriterTask(Deque<Event> deque) {
this.deque = deque;
}
4. Implement the run() method of this task, which contains a loop that traverses 100 times. On each traversal, a new Event object is created, then saved to the queue, and sleeps for 1 second. The code is as follows:
Copy the code code as follows:
@Override
public void run() {
for (int i = 0; i < 100; i++) {
Event event = new Event();
event.setDate(new Date());
event.setEvent(String.format("The thread %s has generated an event",
Thread.currentThread().getId()));
deque.addFirst(event);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
5. Create a class named CleanerTask and inherit the Thread class. The code is as follows:
Copy the code code as follows:
public class CleanerTask extends Thread {
6. Declare a queue attribute used to store events, implement the constructor of the class, and use its parameters to initialize the queue attribute. In the construction method, set the thread as a daemon thread by calling the setDaemon() method. The code is as follows:
Copy the code code as follows:
private Deque<Event> deque;
public CleanerTask(Deque<Event> deque) {
this.deque = deque;
setDaemon(true);
}
7. Implement the run() method. There is an infinite loop in the method body to obtain the current time and then call the clearn() method. The code is as follows:
Copy the code code as follows:
@Override
public void run() {
while (true) {
Date date = new Date();
clean(date);
}
}
8. Implement the clean() method. In this method, get the last time, and then check the time difference between the time and the current time. If it was created 10 seconds ago, delete the current event, and then check the next event. If an event is deleted, the information about the deleted event will be printed out, and the latest length of the queue will also be printed out, so that the execution progress of the program can be observed. The code is as follows:
Copy the code code as follows:
private void clean(Date date) {
long difference;
boolean delete;
if (deque.size() == 0) {
return;
}
delete = false;
do {
Event e = deque.getLast();
difference = date.getTime() - e.getDate().getTime();
if (difference > 10000) {
System.out.printf("Cleaner: %s/n", e.getDate());
deque.removeLast();
delete = true;
}
} while (difference > 10000);
if (delete) {
System.out.printf("Clearner: Size of the queue: %d/n", deque.size());
}
}
9. Create the main class of the program, the Main class, and then implement the main() method. The code is as follows:
Copy the code code as follows:
public class Main {
public static void main(String[] args) {
10. Use the Deque class to create a queue to store events. The code is as follows:
Copy the code code as follows:
Deque<Event> deque = new ArrayDeque<>();
11. Create and start three WriterTask threads and one CleanerTask thread. The code is as follows:
Copy the code code as follows:
Deque<Event> deque = new ArrayDeque<>();
WriterTask writer = new WriterTask(deque);
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(writer);
thread.start();
}
CleanerTask cleaner = new CleanerTask(deque);
cleaner.start();
12. Execute the program and view the execution results.
know why
Analyzing the execution results of the program, we can see that the queue first increases to 30, and then changes between 27 and 30 until the program execution ends.
The program first starts executing from three WriterTask threads. Each thread first adds an event to the queue and then sleeps for 1 second. After the first 10 seconds have passed, there will be thirty events in the queue. During this 10 seconds, when all three WriterTask threads sleep, the CleanerTask thread will also run, but no events will be deleted because the generation time of all events does not exceed 10 seconds. After the first 10 seconds, three WriterTasks add three events to the queue every second; similarly, CleanerTask deletes three events every second. So, the number of events hovers between 27 and 30.
When the WriterTask threads are all sleeping, we are free to process time, allowing the daemon thread to run during this time. If you set the WriterTask thread's sleep time to be shorter, the CleanerTask thread will get less CPU running time. If this is the case, the length of the queue will continue to grow because the CleanerTask thread never gets enough running time to delete enough events.
never ending
The thread can only be set as a daemon thread by calling the setDaemon() method before calling the start() method. Once a thread starts running, the daemon state cannot be modified.
You can also use isDaemon() to check whether a thread is a daemon thread. If it is a daemon thread, it returns true; if it is an ordinary thread, it returns false.
Use doctrine
This article is translated from "Java 7 Concurrency Cookbook" (D Gua Ge stole it as "Java7 Concurrency Example Collection") and is only used as learning materials. It may not be used for any commercial purposes without authorization.
Small success
Complete versions of all sample code used in this section.
Complete code of Event class
Copy the code code as follows:
package com.diguage.books.concurrencycookbook.chapter1.recipe7;
import java.util.Date;
/**
*Event information class
* Date: 2013-09-19
* Time: 22:56
*/
public class Event {
private Date date;
private String event;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getEvent() {
return event;
}
public void setEvent(String event) {
this.event = event;
}
}
Complete code of WriterTask class
Copy the code code as follows:
package com.diguage.books.concurrencycookbook.chapter1.recipe7;
import java.util.Date;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
/**
* Generate an event every second.
* Date: 2013-09-19
* Time: 22:59
*/
public class WriterTask implements Runnable {
private Deque<Event> deque;
public WriterTask(Deque<Event> deque) {
this.deque = deque;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
Event event = new Event();
event.setDate(new Date());
event.setEvent(String.format("The thread %s has generated an event",
Thread.currentThread().getId()));
deque.addFirst(event);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Complete code of CleanerTask class
Copy the code code as follows:
package com.diguage.books.concurrencycookbook.chapter1.recipe7;
import java.util.Date;
import java.util.Deque;
/**
* Event cleanup
* Date: 2013-09-19
* Time: 23:33
*/
public class CleanerTask extends Thread {
private Deque<Event> deque;
public CleanerTask(Deque<Event> deque) {
this.deque = deque;
setDaemon(true);
}
@Override
public void run() {
while (true) {
Date date = new Date();
clean(date);
}
}
/**
* Delete event.
*
* @param date
*/
private void clean(Date date) {
long difference;
boolean delete;
if (deque.size() == 0) {
return;
}
delete = false;
do {
Event e = deque.getLast();
difference = date.getTime() - e.getDate().getTime();
if (difference > 10000) {
System.out.printf("Cleaner: %s/n", e.getDate());
deque.removeLast();
delete = true;
}
} while (difference > 10000);
if (delete) {
System.out.printf("Clearner: Size of the queue: %d/n", deque.size());
}
}
}
The complete code of Main class
Copy the code code as follows:
package com.diguage.books.concurrencycookbook.chapter1.recipe7;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* Date: 2013-09-19
* Time: 23:54
*/
public class Main {
public static void main(String[] args) {
Deque<Event> deque = new ArrayDeque<>();
WriterTask writer = new WriterTask(deque);
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(writer);
thread.start();
}
CleanerTask cleaner = new CleanerTask(deque);
cleaner.start();
}
}