java multithreading the Thread constructor (source code analysis)

In the previous article on the state of the life cycle of the thread and the common thread api we had a narrator. This article began to be focused on a description of its construction method, it will also be announced why we call the start method will be able to start a thread.

First, the daemon thread and non-daemon thread

We get the thread id will find the time every time is not 0, this is because when the java virtual machine running a thread will be the default start some other thread to thread for our service. And the thread created by default create our own there is a distinction. It is necessary to distinguish between non-daemon daemon thread and the thread.

1. What is a daemon thread and non-daemon thread?

These default startup thread is a daemon thread, he specifically deal with some background work. For example, garbage collection and so on. These non-daemon thread is a thread of our own creation. Official documentation states that, when the java virtual machine no non-daemon thread, and the thread will exit the default. For example you can understand:

Like daemon thread inside the hotel staff, non-daemon thread like a customer, the customer is not, then there is no attendant longer necessary.

2, code demonstrates

We look through the code to demonstrate their role,

public class Test {
	public static void main(String[] args) {
		Thread thread = new Thread(()->{
			while (true) {
				System.out.println("无限循环");
			}
		}) ;
		thread.start();
	}
}
复制代码

Here there are two main threads is a main thread, the second thread is created yourself. After running it is clear that the implementation of the program will go on the radio, because the thread is non-daemon threads. Even the main thread of execution will be the end of a thread execution. Now we set the thread as a daemon thread is not the same.

public class Test {
	public static void main(String[] args) {
		Thread thread = new Thread(()->{
			while (true) {
				System.out.println("无限循环");
			}
		}) ;
		//设置为守护线程
		thread.setDaemon(true);
		thread.start();
	}
}
复制代码

In the run again, we will find that out of the normal procedure, it is because we set the thread became a daemon thread, you think about the main thread and thread have become a waiter, and now no customers, so these daemon threads to shop I was wandering around and left.

3, daemon thread scenario?

After you understand the characteristics of a daemon thread, you can use this principle to do something unexpected, such as when exiting jvm also wanted to withdraw some threads to follow, you can put him set up as a daemon thread.

After this basic understanding of the concepts we look at the constructor thread.

Second, the thread constructor

1, the constructor

Thread Thread constructors have a total of eight,

Here we come into contact with a new class ThreadGroup. Meaning it represents is a thread belongs to the thread group. In the above we can see in the example of a thread when the thread can either specify the thread group belongs, can also declare its runnable interface. Let's analyze this thread group ThreadGroup.

The relationship between the two of them can be expressed this way:

In the above said we can specify the thread where the thread group, here we show you the code.

public class Test {
	public static void main(String[] args) {
		//为当前线程设置线程组
		ThreadGroup group= new ThreadGroup("线程组");
		Thread thread = new Thread(group,"当前线程");
		thread.start();
		System.out.print(thread.getThreadGroup().getName());
	}
}
//输出:线程组
复制代码

This is its basic usage, but if we do not belong to the thread group output thread specified what would be the result? have a test:

public class Test {
	public static void main(String[] args) {
		ThreadGroup group= new ThreadGroup("线程组");
		ThreadGroup maingroup = Thread.currentThread().getThreadGroup();
		
		Thread thread1 = new Thread(group,"线程A");
		Thread thread2 = new Thread("线程B");
		System.out.println(thread1.getThreadGroup().getName());
		System.out.println(thread2.getThreadGroup().getName());
		System.out.println(maingroup.getName());
	}
}
//输出:线程组 main main
复制代码

The above code mean is this, specify the thread A thread group we created, the default thread B thread group, maingroup is the main thread group. The output indicates that we will find, if you do not specify a thread thread group, then he and his father's thread group is the same.

2, a thread instantiated

Given above eight constructor thread, we can use these eight constructor to instantiate a thread, but the bottom is how to do it? Could it be that as the general category as an example of it? In this regard we need to look deep source thread:

public Thread(ThreadGroup group, Runnable target, String name, long stackSize) {
    init(group, target, name, stackSize);
}
复制代码

We chose one of the most complex construction method, because other construction methods are a subset of, we can see here is actually calling the init method, that is truly the initialization is done in the init method. We might as well go with a look:

private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
    init(g, target, name, stackSize, null, true);
}
复制代码

The init method there is also one, but more than two out of the parameters. Want to find out we need to talk to go in and see:

    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        //第一部分:确保线程名字不为空
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
        this.name = name;
        //第二部分:指定线程组
        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        if (g == null) {
            if (security != null) {
                g = security.getThreadGroup();
            }
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }
        g.checkAccess();
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }
        g.addUnstarted();
        this.group = g;
        //第三部分:一些其他参数设置
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        //第四部分:runnable接口配置
        this.target = target;
        setPriority(priority);
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        //第五部分:设置栈大小
        this.stackSize = stackSize;

        //第六部分:设置线程ID
        tid = nextThreadID();
    }

复制代码

Finally we found a way to initialize the thread. We divided into five parts:

(1) Part I: thread-name can not be empty,

Here one would have to mention the name of the thread, java official asked us if the developer does not appear to specify a name for the thread, the thread will be "Thread-" prefixed to digital suffix, consisting of the name of the thread. But in any case we need to have a thread name.

(2) Part II: Specifies the current thread's thread group

Inside the code is very clear, that if g is not empty, we are using this as a thread group g current thread, otherwise it will use the thread group parent class. Of course, in the middle but also check the permissions issue and so on.

(3) Part III: Other Configuration

Here the configuration is set to daemon thread, priority, class loader and so on.

(4) Part IV: runnable interface configuration

Specify implements runnable interface class.

(5) Part V: Sets the stack size

Thread stack size can be seen that according to the default size of argument zero transfer process, i.e. the default size of the thread stack

(6) Part VI: Set the thread id

Thread ID is specified in the nextThreadID method. We can look at how to specify the thread ID.

private static synchronized long nextThreadID() {
    return ++threadSeqNumber;
}
复制代码

We can see, in fact, threadSeqNumber.

OK, the above is how to initialize a thread, I believe we are quite clear, the other parameters of this constructor init method just made some changes in it. But the principle is the same. One problem mentioned in the previous article has not yet been resolved, read on.

Third, why start method is called will be able to start a thread

To solve this problem we also have to look at the source code in depth (jdk1.8):

   public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
复制代码

What do these codes mean? Will first determine whether the thread state is abnormal, then the current thread is added to the thread group before starting, start0 formal method of starting a thread last call. Now the key here, is this really started threads start0 method, we might as well go in catching look:

That is the real start of native method to start, seems to be no method calls run, why run method is executed inside the content of it. The official document is so explained: JNI method calls inside start0 run method. Such a sentence is to explain the reasons above.

As already solved two problems, the first is the constructor, and the second also understand why we call the start method will be able to start a thread rather than run. We analyze the source code can know, api method provides a thread of substantially all the native of.

Guess you like

Origin juejin.im/post/5d5bb572f265da03bd051eb9