Welcome to the second in a series on Concurrency.

In the previous “How to Create Multithreading” article, we’ve visually seen how to create a Thread in Java using Thread and Runnable, so you’ve got some sense of how to do it. In this article, we’ll build on the previous sample code and give you the necessary instructions on threading to help you understand threads at a more basic level and to lay the groundwork for future studies.

First, recognize the thread from the process

Until the mid-1980s, processes were the basic units of an operating system that had resources and ran independently. However, with the development of computers, the increasing demand for operating system throughput, and the development of multiple processors, the process as the basic dispatching unit has become more and more inappropriate, because it is too heavy.

When we create processes, we need to create PCBS for them and allocate all the resources we need, such as memory space, I/O devices, and so on. However, when switching processes, the system also needs to retain the current process’S CPU environment and set up the new process’s CPU environment, which takes time. In other words, the process of creating, switching, and destroying processes, the system has to spend a lot of time. As a result, you can’t set up too many processes in an operating system, and you can’t switch frequently. Obviously, this does not meet the needs of the development of The Times.

Therefore, with the huge overhead of process switching and the development of multi-core cpus, threads were born.

Conceptually, a thread can be understood as the basic unit of an operating system that runs independently, and a process can have multiple threads. Also, threads have many of the same properties as processes, so they are sometimes called light-weight processes.

Why are threads relatively lightweight

Before threads, the system needed to switch processes when switching tasks, which was costly. However, after the introduction of threads, the thread belongs to the process, the process is still the owner of resources, and the thread only occupies a small amount of resources. At the same time, thread switching does not lead to process switching, so the cost is small. In addition, processes and threads can execute concurrently, resulting in better concurrency for the operating system, which can effectively improve system resource utilization and system throughput.

2. Thread – the Thread foundation in Java

In the first part of this article, we looked at threading at the operating system level. In Java, we need to recognize threads through the Thread class, including some of its basic properties and basic methods. Thread is the foundation of the Java multithreading foundation, so don’t ignore it just because it’s simple.

The following diagram summarizes the core properties and methods of the Thread class:

1. How to construct threads in Thread

There are nine common constructors for Thread. We don’t need to be familiar with all of them.

  • Thread()The constructor will generate one by defaultThread-+nThe name,nIs by internal methodnextThreadNum()An integer number generated;
  • Thread(String name)It is a good practice to specify the thread name when building the thread;
  • Thread(Runnable target)And the incomingRunnableAn example of “, “which we showed in the previous article;
  • Thread(Runnable target, String name)In the incomingRunnableInstance specifies the thread name.

2. Key attributes in Thread

frominit()Method to understand the construction of threads

Although Thread has nine constructors, they are all ultimately constructed through the following init() method, so understanding this method will help you understand the construction process of Thread.


    /**
     * Initializes a Thread.
     *
     * @param g the Thread group
     * @param target the object whose run() method gets called
     * @param name the name of the new Thread
     * @param stackSize the desired stack size for the new thread, or
     *        zero to indicate that this parameter is to be ignored.
     * @param acc the AccessControlContext to inherit, or
     *            AccessController.getContext() if null
     * @param inheritThreadLocals if {@code true}, inherit initial values for
     *            inheritable thread-locals from the constructing thread
     */
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals)
Copy the code

There are dozens of lines of code for the init() method, but to save space, we only post the signature of the method here. You can see the body of the method for yourself. In the method signature, there are several important arguments:

  • g: Indicates the thread group to which the thread belongs. A thread group is a collection of threads with similar behavior;
  • targetInherited:RunnableObject instance of;
  • name: Thread name;

The other parameters usually do not need to be customized. Keep the default values. If you look at the init() method body code, you can see that init() initializes the following properties:

  • name: Thread name;
  • group: The thread group to which the thread belongs;
  • daemon: Whether it is a daemon process.
  • priority: Priority of the thread;
  • tid: thread ID;

About the name

Although Thread generates a Thread name by default, it is recommended that you manually set the name when creating the Thread for logging purposes and troubleshooting. For example, anQiLaPlayer can be set to thread-anqila.

About Thread IDS

Like Thread names, each Thread has its own ID, and if you do not specify one, the Thread will be generated automatically. Specifically, the Thread ID is obtained by adding threadSeqNumber() to the static variable threadSeqNumber:

private static synchronized long nextThreadID(a) {
    return ++threadSeqNumber;
}
Copy the code

About thread priorities

When a new thread is created, the priority of the thread is the same as that of the current parent thread by default, or setPriority(int newPriority) can be set. However, there are two important points to note when setting thread priorities:

  • The priority setting of threads is unreliable: we can specify the priority of threads by number, but the order of execution is determined by the operating system, because the priority setting of threads does not correspond to all operating systems.
  • Thread group priority is higher than thread priority: each thread has a thread group, and we cannot set a thread priority number that is higher than the thread group priority. If so, the priority of the thread group will be used directly.

3. Key methods in the thread

Some of the most important methods in Thread usage, such as start(), join(), sleep(), yield(), or interrupted(), will be explained in the following article in conjunction with the state of the Thread. Note that notify(), wait(), and so on are not methods of Thread; they are methods of Object.

3. Application scenarios of multithreading

From the previous analysis, we’ve learned about threads both at the operating system level and in Java. So, what scenarios should you consider using multithreading?

In general, you need to consider multithreading when you encounter the following two types of scenarios:

1. The asynchronous

When two separate logical units do not need to be completed in synchronous order, they can be processed asynchronously through multiple threads.

For example, users sign up and send email messages. Obviously, registering and sending messages are two separate logical units. After registering, we can start another thread to send the messages, thus achieving logical decoupling and shortening the response time of the registering unit.

2. Concurrent computers are basically multi-core processors, which can be used to speed up processing by multiple threads when processing batch tasks.

For example, suppose the system needs to send messages to a million users. You can imagine that a single threaded process would take years to complete. At this point, we can greatly improve efficiency by creating multiple threads from thread pools.

Note that for some of you, you may not have been exposed to multithreading scenarios. However, please do not ignore the application of multithreading because the work scene is simple or the amount of data is low. Multithreading is widely used in all kinds of middleware and big Internet factories around you.

Risk tips when applying multithreading

Although multithreading has many benefits, it still needs to be analyzed objectively according to the scenario. Unreasonable use of multithreading will increase the security risk and maintenance risk of the system. So, when using multithreading, make sure the scenario makes sense and that it’s within your technical capabilities.

That’s all for the text, congratulations on another star!

The teacher’s trial

  • Using different constructs, write two threads and print out the key information for each thread.
  • Retrieve data and compare the differences between processes and threads in detail.

Further reading and references

  • “King concurrent course” outline and update progress overview

About the author

Pay attention to [technology 8:30], get the article updates in time. Pass on quality technical articles, record the coming-of-age stories of ordinary people, and occasionally talk about life and ideals. 8:30 in the morning push author quality original, 20:30 in the evening push industry depth good article.

If this article is helpful to you, welcome to like, follow, supervise, we together from bronze to king.