This article mainly studies related issues of background threads in Java, as follows.
I have never heard of it before that there are background threads in Java. Generally speaking, JVM (JAVA virtual machine) generally includes two types of threads, namely user thread and background thread. The so-called daemon thread refers to a thread that provides a common service in the background when the program is running, and this thread is not an indispensable part of the program. Therefore, when all non-background threads end, that is, when the user threads end, the program terminates. At the same time, it will kill all background threads in the process. Conversely, as long as any non-background threads are still running, the program will not end. It is better to execute main() than a non-backend thread.
Based on this feature, when all user threads in the virtual machine exit from running, the daemon thread does not have service objects, the JVM exits.
This is explained in the JDK source code.
* Marks this thread as either a {@linkplain #isDaemon daemon} thread
* or a user thread. The Java Virtual Machine exits when the only
* threads running are all daemon threads.
1. Conditions for starting a background thread:
/*The SetDaemon() method must be called before starting the thread to set this thread as a background thread. * In this program, after we enter a string, the Main thread will stop running* Then there is no thread for the user that can run in the program. So the background thread will be stopped * The JVM will be stopped, and interested readers can try it yourself */public class DaemonRunner implements Runnable {@Override public void run() {while (true) {for (int i = 0; i < 3; i++) {System.out.println("Daemon Thread" + i);}}} public static void main(String[] args) {Thread daemon = new Thread(new DaemonRunner());daemon.setDaemon(true);daemon.start();Scanner s = new Scanner(System.in);String string=s.nextLine();Runtime.getRuntime().addShutdownHook(new Thread(){@Override public void run() {super.run();System.out.println("JVM Exit");try {TimeUnit.MILLISECONDS.sleep(50);}catch (InterruptedException e) {e.printStackTrace();}}});}}2. All threads started in the background thread belong to the background thread. Although you don't explicitly specify that they are background threads, they are indeed background threads.
/* You can determine whether the thread is a background thread by calling the isDaemon() method. If it is a background thread, * then any thread it creates is automatically set to the background thread* In this example, the Daemon thread is set to the background mode and then derives many child threads. These threads are not set to the * background mode, but they are indeed background threads. Then, the Daemon thread enters an infinite loop and calls the yield method in the loop* to hand over the control to other threads or processes*/class Daemon implements Runnable{private Thread[] t = new Thread[10];@Override public void run() {for (int i = 0; i < t.length; i++) {t[i] = new Thread(new DaemonSpawn());t[i].start();System.out.println("DaemonSpawn " + i + "started");}for (int i = 0; i < t.length; i++) {System.out.println("t[" + i + "].isDaemon" + t[i].isDaemon());}while (true) {Thread.yield();}}}class DaemonSpawn implements Runnable{@Override public void run() {while (true) {Thread.yield();}}}public class Daemons {public static void main(String[] args) {Thread d = new Thread(new Daemon());d.setDaemon(true);d.start();System.out.println("d.isDaemon()=" + d.isDaemon());try {TimeUnit.SECONDS.sleep(1);//Let the thread in the startup background gets a certain execution time. }catch (InterruptedException e) {e.printStackTrace();}}}The final execution results are as follows:
d.isDaemon()=true
DaemonSpawn 0started
DaemonSpawn 1started
DaemonSpawn 2started
DaemonSpawn 3started
DaemonSpawn 4started
DaemonSpawn 5started
DaemonSpawn 6started
DaemonSpawn 7started
DaemonSpawn 8started
DaemonSpawn 9started
t[0].isDaemontrue
t[1].isDaemontrue
t[2].isDaemontrue
t[3].isDaemontrue
t[4].isDaemontrue
t[5].isDaemontrue
t[6].isDaemontrue
t[7].isDaemontrue
t[8].isDaemontrue
t[9].isDaemontrue
3. Specify a ThreadFactory object by specifying Executors.newCachedThreadPool() method. In this way, we can also set the thread we want to start as a background thread.
/*In this example, for this static constructor: Executors.newCachedThreadPool(new DaemonThreadFactory()* We can pass in a ThreadFactory object, so we can set the thread we want to start as a background thread through this method* This is to be noted.*/class DaemonThreadFactory implements ThreadFactory{@Override public Thread newThread(Runnable r) {Thread t = new Thread(r);t.setDaemon(true);return t;}}/*In this example, in the Main method, the ordinary method in the Main method will be called first, " System.out.println("All dameons started");"* So this statement will be printed first. Then during the main thread sleeps, the corresponding background thread will get the execution time. Finally, when the Main thread* ends running, that is, when the Main thread recovers from sleep, the Main line will end the run. Then * then all the background threads will stop. The JVM will also stop executing. */public class DaemonFromFactory implements Runnable {@Override public void run() {try {while (true) {TimeUnit.MILLISECONDS.sleep(100);System.out.println(Thread.currentThread() + " " + this);}}catch (InterruptedException e) {System.out.println("Interrupted");}}public static void main(String[] args) {ExecutorService exec = Executors.newCachedThreadPool(new DaemonThreadFactory()); for (int i = 0; i < 10; i++) {exec.execute(new DaemonFromFactory());}System.out.println("All dameons started");try {TimeUnit.MILLISECONDS.sleep(500);}catch (InterruptedException e) {e.printStackTrace();}}}The final output result is:
All dameons started
Thread[Thread-3,5,main] Concurrency.DaemonFromFactory@56214c1
Thread[Thread-2,5,main] Concurrency.DaemonFromFactory@5724147d
Thread[Thread-0,5,main] Concurrency.DaemonFromFactory@144fe080
Thread[Thread-1,5,main] Concurrency.DaemonFromFactory@104fa29e
Thread[Thread-8,5,main] Concurrency.DaemonFromFactory@5b069a7f
Thread[Thread-9,5,main] Concurrency.DaemonFromFactory@1a7288d1
Thread[Thread-7,5,main] Concurrency.DaemonFromFactory@25144c3e
Thread[Thread-4,5,main] Concurrency.DaemonFromFactory@288523d
Thread[Thread-6,5,main] Concurrency.DaemonFromFactory@1edae2a8
Thread[Thread-5,5,main] Concurrency.DaemonFromFactory@626007aa
Thread[Thread-3,5,main] Concurrency.DaemonFromFactory@56214c1
Thread[Thread-2,5,main] Concurrency.DaemonFromFactory@5724147d
Thread[Thread-6,5,main] Concurrency.DaemonFromFactory@1edae2a8
Thread[Thread-5,5,main] Concurrency.DaemonFromFactory@626007aa
Thread[Thread-4,5,main] Concurrency.DaemonFromFactory@288523d
Thread[Thread-9,5,main] Concurrency.DaemonFromFactory@1a7288d1
Thread[Thread-7,5,main] Concurrency.DaemonFromFactory@25144c3e
Thread[Thread-8,5,main] Concurrency.DaemonFromFactory@5b069a7f
Thread[Thread-1,5,main] Concurrency.DaemonFromFactory@104fa29e
Thread[Thread-0,5,main] Concurrency.DaemonFromFactory@144fe080
Thread[Thread-2,5,main] Concurrency.DaemonFromFactory@5724147d
Thread[Thread-3,5,main] Concurrency.DaemonFromFactory@56214c1
Thread[Thread-6,5,main] Concurrency.DaemonFromFactory@1edae2a8
Thread[Thread-1,5,main] Concurrency.DaemonFromFactory@104fa29e
Thread[Thread-0,5,main] Concurrency.DaemonFromFactory@144fe080
Thread[Thread-7,5,main] Concurrency.DaemonFromFactory@25144c3e
Thread[Thread-8,5,main] Concurrency.DaemonFromFactory@5b069a7f
Thread[Thread-5,5,main] Concurrency.DaemonFromFactory@626007aa
Thread[Thread-9,5,main] Concurrency.DaemonFromFactory@1a7288d1
Thread[Thread-4,5,main] Concurrency.DaemonFromFactory@288523d
Thread[Thread-2,5,main] Concurrency.DaemonFromFactory@5724147d
Thread[Thread-3,5,main] Concurrency.DaemonFromFactory@56214c1
Thread[Thread-8,5,main] Concurrency.DaemonFromFactory@5b069a7f
Thread[Thread-7,5,main] Concurrency.DaemonFromFactory@25144c3e
Thread[Thread-4,5,main] Concurrency.DaemonFromFactory@288523d
Thread[Thread-6,5,main] Concurrency.DaemonFromFactory@1edae2a8
Thread[Thread-1,5,main] Concurrency.DaemonFromFactory@104fa29e
Thread[Thread-0,5,main] Concurrency.DaemonFromFactory@144fe080
Thread[Thread-9,5,main] Concurrency.DaemonFromFactory@1a7288d1
Thread[Thread-5,5,main] Concurrency.DaemonFromFactory@626007aa
Thread[Thread-3,5,main] Concurrency.DaemonFromFactory@56214c1
Thread[Thread-2,5,main] Concurrency.DaemonFromFactory@5724147d
Thread[Thread-8,5,main] Concurrency.DaemonFromFactory@5b069a7f
4. First of all, you should realize that if the user thread suddenly exits, the background thread will terminate its run method without executing the finally clause.
/*When you call this program, you will see that the finally clause will not be executed, but if you comment out the call to setDaemon(), you will see that the * finally clause will be executed.* This behavior is correct. Even if you do not want this behavior based on the promise you finally gave in front of you. But this is the case. When the last non-background thread terminates, the background thread will suddenly stop. Because once main() exits, the JVM will immediately close all * threads in the background. Because you can't close background threads in an elegant way, they're hardly a good idea. Non-backend Executors are usually a * better way, because all tasks controlled by Executor can be closed at the same time. */class ADaemon implements Runnable{ @Override public void run() { System.out.println("Starting ADaemon"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { System.out.println("Exiting via InterruptedException"); } finally { System.out.println("This should always run?"); } }}public class DaemonsDontRunFinally { public static void main(String[] args) { Thread t = new Thread(new ADaemon()); t.setDaemon(true); t.start(); }} The final output results are as follows:
Starting ADaemon
However, if the situation becomes the following situation, the output results will be different again:
class ADaemon implements Runnable{ @Override public void run() { System.out.println("Starting ADaemon"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { System.out.println("Exiting via InterruptedException"); } finally { System.out.println("This should always run?"); } }}public class DaemonsDontRunFinally { public static void main(String[] args) { Thread t = new Thread(new ADaemon()); t.setDaemon(true); t.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }}Since the main thread does not exit suddenly, the background thread gets the execution time during the main thread sleeps, so the final print result is:
Starting ADaemon
This should always run?
The above is all the content of this article about the analysis of background thread instances in Java, and I hope it will be helpful to everyone. Interested friends can continue to refer to other related topics on this site. If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!