Java Multithreading series 7.

Let’s talk about another thread feature: daemon thread or user thread?

Let’s start by looking at the comments for the Thread.setdaemon () method, as shown below.

1. Marks this thread as either a daemon thread or a user thread.

  1. The Java Virtual Machine exits when the only threads running are all daemon threads.
  2. This method must be invoked before the thread is started.

There are three points of information in it, to explain one by one:

The official features

1. User thread or daemon thread?

Java threads are divided into two classes. One is the user thread, which is the default when we create threads, with the property daemon = false. The other is the daemon thread, which is what happens when we set daemon = true.

The general relationship between the two is that the user thread is the thread running in the foreground, and the daemon thread is the thread running in the background. In general, the daemon thread is to provide some services for the user thread. In Java, for example, we often refer to GC memory reclamation threads as daemon threads.

2. JVM co-exists with user threads

The JVM exits when all user threads have finished executing and only daemons are running. Read online materials and some books, all have this sentence, but also only have this sentence, did not explain why, as if this sentence has become a theorem, do not need to prove the appearance. Since we recently set up a JVM Debug environment, we had to check it out. (It took a long time to find out.)

We see the JVM source thread. CPP file, and here is the code to implement threads. There is a place that monitors the number of non-daemons. How else would you know that there are only daemons left? Most likely in the thread removal method. With that in mind, let’s look at the file’s remove() method. Here’s the code.

Void Threads::remove(JavaThread* p, bool is_daemon) { // Reclaim the ObjectMonitors from the omInUseList and omFreeList of the moribund thread. ObjectSynchronizer::omFlush(p); /** * create a monitor lock object ml */ / so we can check // that we do not remove thread without safepoint code notice { MonitorLocker ml(Threads_lock); assert(ThreadsSMRSupport::get_java_thread_list()->includes(p), "p must be present"); // Maintain fast thread list ThreadsSMRSupport::remove_thread(p); _number_of_threads--; if (! Is_daemon) {/** * number of non-daemon_threads minus 1 */ _number_of_non_daemon_threads--; /** * when the number of non-daemons is 1, Wake up the thread waiting in the destroy_vm() method */ / Only one thread left, do a notify on the Threads_lock so a thread waiting // on destroy_vm will wake up. if (number_of_non_daemon_threads() ==  1) { ml.notify_all(); }} / ThreadService::remove_thread(p, is_daemon); // Make sure that safepoint code disregard this thread. This is needed since // the thread might mess around with locks after this point. This can cause it // to do callbacks into the safepoint code. However, the safepoint code is not aware // of this thread since it is removed from the queue. p->set_terminated_value(); } // unlock Threads_lock // Since Events::log uses a lock, we grab it outside the Threads_lock Events::log(p, "Thread exited: " INTPTR_FORMAT, p2i(p)); }Copy the code

I put some comments in there, and you can see that, sure enough, there is a count of the number of non-daemons, and when the non-daemons are 1, it wakes up the threads waiting in the destory_vm() method, We confirm that we have found code for threads that trigger a wake up to monitor JVM exit when the number of non-daemons is 1. Next we look at the destory_vm() code, again in the thread.cpp file.

bool Threads::destroy_vm() { JavaThread* thread = JavaThread::current(); #ifdef ASSERT _vm_complete = false; #endif /** * Wait until we are the last non-daemon thread to execute {MonitorLocker nu(Threads_lock); While (Threads:: number_of_non_DAemon_threads () > 1) /** * the number of non-daemon Threads is greater than 1, */ / This wait should make safepoint checks, wait without a timeout, // and wait as a suspend-equivalent condition. nu.wait(0, Mutex::_as_suspend_equivalent_flag); } /** * the following code is the logic to shut down the VM */ EventShutdown e; if (e.should_commit()) { e.set_reason("No remaining non-daemon Java threads"); e.commit(); }... Omit the rest of the code}Copy the code

We saw here that when the number of non-daemons is greater than 1, it waits until there is one non-daemon thread left, and then exits the JVM when the thread is finished executing. When do you call destroy_vm() when you have another point to locate? Again, by looking at the code and comments, you can see that this is triggered after the main() method has finished executing.

In the JavaMain() method of the java.c file, the LEAVE() method is finally called, which calls (* VM)->DestroyJavaVM(vm); To trigger the JVM to exit, eventually calling the Destroy_vm () method.

#define LEAVE() \ do { \ if ((*vm)->DetachCurrentThread(vm) ! = JNI_OK) { \ JLI_ReportErrorMessage(JVM_ERROR2); \ ret = 1; \ } \ if (JNI_TRUE) { \ (*vm)->DestroyJavaVM(vm); \ return ret; \ } \ } while (JNI_FALSE)Copy the code

So we also know why the main thread can exit before its subthreads. Although destroy_vm() is called before the main thread exits, the JVM waits in destroy_vm() for the non-daemon thread to finish executing. If the child thread is a non-daemon thread, the JVM waits and does not exit immediately.

Let’s summarize this point: Java programs will trigger JVM exit when the main thread exits, but the JVM exit method Destroy_vm () will wait for all non-daemons to finish executing. Numberofnondaemonthreads counts the numberof non-daemons. This variable adds and subtracts when a thread is added or deleted.

Another derivative is that when the JVM exits, any remaining daemons are discarded, and neither the finally part of the code nor the stack unwound operation (that is, no catch) is performed. This is obvious, the JVM exits, the daemon thread exits naturally, and of course this is a feature of daemon threads.

Is it a boy or a girl? Born to be

Whether a thread is a user thread or a daemon thread must be determined before the thread is started. Before the start() method is called, it is an object that is not mapped to any thread in the JVM, so you can change the daemon properties. After the start() method is called, a thread in the JVM maps the thread object, so you cannot change it.

Other features

1. Daemon thread attributes inherit from the parent thread

Thread constructor () : Thread constructor () : Thread constructor () : Thread constructor ()

private Thread(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { ... This.daemon = parent.isdaemon (); . Omit a bunch of code}Copy the code

2. The daemon thread has a lower priority than the user thread

I also doubt it when I see many books and materials that say so. So I wrote the following code to test whether the daemon thread has a lower priority than the user thread.

public class TestDaemon { static AtomicLong daemonTimes = new AtomicLong(0); static AtomicLong userTimes = new AtomicLong(0); public static void main(String[] args) { int count = 2000; List<MyThread> threads = new ArrayList<>(count); for (int i = 0; i < count; i ++) { MyThread userThread = new MyThread(); userThread.setDaemon(false); threads.add(userThread); MyThread daemonThread = new MyThread(); daemonThread.setDaemon(true); threads.add(daemonThread); } for (int i = 0; i < count; i++) { threads.get(i).start(); } try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } system.out.println ("daemon: "+ daemontimes.get ()); System.out.println("user count: "+ usertimes.get ()); System.out.println(" daemontimes.get () -usertimes.get ()) + "ms"); } static class MyThread extends Thread { @Override public void run() { if (this.isDaemon()) { daemonTimes.getAndAdd(System.currentTimeMillis()); } else { userTimes.getAndAdd(System.currentTimeMillis()); }}}}Copy the code

The result is as follows.

Result 1: Daemon statistics: 1570785465411405 User Statistics: 1570785465411570 Time difference between Daemon and user: -165ms Result 2: Daemon statistics: 1570786615081403 user statistics: 1570786615081398 daemon time difference: 5msCopy the code

It’s not surprising that the difference is so close, but in this case I can’t define that the daemon thread and the user thread have the same priority. The JVM code has not found that the daemon thread priority is lower than the user thread, this point is still suspicious, there are friends can leave a message to say some, mutual exchange learning.

conclusion

To summarize the points made in this article, one is that threads are divided into two types: user threads and daemon threads. To make a thread daemons, you need to set the daemon property before the thread calls the start() method. There is also a JVM source analysis of why the JVM automatically exits when all user threads are finished executing. The parent thread is the daemon thread, so the child thread is the daemon thread by default; In addition to some books and materials said that the daemon thread priority is lower than the user thread put forward their own questions, and hope to understand the friends can help answer.

If you feel that this article has a harvest, trouble point in the look, support, the original is not easy.

Recommended reading

After years of writing Java code, finally debug into the JVM

Original | so the simplest openjdk13 latest code compilation

Understand the Java thread priority, but also the corresponding operating system priority, otherwise you will step on the pit

The most basic knowledge of threads

The boss told you to stop blocking

You can eat fast food and learn serial, parallel, and concurrency

Make a cup of tea and learn asynchrony

How much do we know about the process?

Design patterns seen and forgotten, forgotten and read?

If you reply “Design Mode”, you can get the ebook “One Story one Design Mode”

Think the article is useful to help forward & praise, thank you friends!

This article is published by OpenWrite!