Multithreaded programming, or concurrent programming to a larger extent, is a very complex and error-prone way of programming, but why take the risk of learning the hard way about various multithreaded programming techniques and solving various concurrency problems?

Because concurrency is the basis of the entire distributed cluster, the distributed cluster can not only greatly reduce the price of equivalent load capacity, but also greatly increase the overall scalability of the maximum load capacity. Low service costs have led to an explosion of ideas in the Internet industry. Any one person can create and maintain an application that serves hundreds or even tens of thousands of people. The high service capacity ceiling makes it possible for countless businesses to be transformed online, greatly broadening the boundary between Internet technology and business.

Multithreaded programming is the foundation and core of this wide range of concurrent technology. Most abstract concurrent problems are conceived and solved based on multithreaded model. And the nature of these concurrent problems is the same, whether thread concurrency, process concurrency or server level concurrency have similar characteristics and face similar problems, multithreaded programming is the best way to get into this area, learn concurrency problem solutions. Therefore, in today’s computer industry, multithreaded programming is not only an important knowledge field for Java programmers to interview and advance, but also an entrance ticket for backend programmers to open the door of distributed systems. If you cannot understand the characteristics and problems of concurrent programs, it is difficult to be competent in the development of distributed systems.

This article is part of a series of articles, so no multithreaded foundation is required. This article will introduce Java multithreaded programming in a reasonable order step by step, from simple to deep to explain the concept of multithreaded programming, use, principle and implementation. In each section, there is a brief introduction to the relevant topic, with links to in-depth articles on the topic. It is recommended that readers who do not know the relevant topic can read the linked articles to understand. But if some of the content in the middle of the article is already very familiar, then you can skim it, ignore the link to the article, can completely use this part of the content as a review outline.

Next, we will systematically understand the Java multithreaded programming knowledge system in this article, from the most basic basic concepts, the use of threads began to speak, all the way to cover the correctness of multithreaded and operational efficiency related issues, to help you from 0 to the entry to master a variety of multithreaded programming skills. After that, the article will become more complex, with in-depth discussions on deadlock resolution, event-driven models, low-level implementations of synchronization mechanisms, thread pool source code parsing, and other advanced topics to help readers better understand what’s going on and not be afraid of multithreaded issues.

Multithreading basics

The concept of concurrency

Multithreading is first of all a means of concurrency, so we first need to understand the basic concept of concurrency. Concurrency is when multiple actuators perform different tasks at the same time. If these tasks need to access the same data, there will be data contention. If concurrency control is not done properly, data race problems can lead to errors in the program’s final results, often referred to as data inconsistencies. For example, account A has three deductions to make at the same time, so if three threads perform the deduction operation at the same time, it is possible that all three threads subtract A value from the original account balance to calculate three results and save them in the account balance, thus causing the deduction results to overwrite each other. There are other more important distributed concurrent multi-threaded concurrent themes, including atomic, critical region, the mutex, compensation, out tasks, and so on professional terms, these can be in this struggle with specific technical details, only through living examples to explain the concept of concurrent post “when we say” concurrent, multithreading, “what?” To find the answer.

Fundamentals of Multithreaded programming

Once we understand the basic concepts of concurrency, we can look at specific techniques in the multithreaded programming world. First of all, why do we need multithreading? What problem does multithreading solve? From there, we’ll get down to writing actual Java multithreaded programming code. We’ll start by creating and running threads directly using the Thread class. Immediately we run into the problem of multi-threading, which requires thread synchronization to ensure that the final output is correct.

In “this time, let us fully master Java multithreading” in this article, we started from the use of multithreading scenarios, only to understand what kind of role multithreading can play in the end we can really use this important technology in practice. We’ll then create and run threads using Thread, and then implement mutually exclusive access to critical sections using the basic Sychronized keyword to implement the first proper Java multithreaded program in this series of articles.

Use of thread pools

In actual development, however, we rarely create the Thread represented by the Thread class and manage its execution. Instead, we give the task to a thread pool and let the thread pool manage the task scheduling and thread lifecycle itself. The thread pool is like a big butler, and as long as we set the rules and budget for it, it automatically handles all kinds of tasks for us. To make good use of thread pools, all you need to do is read the article “Playing with Thread Pools from 0 to 1”!

Problems faced by multithreaded programs

Multithreaded programs face more complex problems than single-threaded programs, which is like cleaning a beehive. We want the sweetness of honey, but we need to be careful not to get stung all over our faces. Generally speaking, multithreaded programs face three kinds of problems: correctness, efficiency and deadlock.

Correctness problem

Correctness is the core of the program, if the results of a program may be wrong, then the value of the program will be greatly reduced, or even directly zero. We have dealt with data contention in multithreaded concurrency using the synchronized keyword in previous articles. However, in the real development process, we will encounter many different concurrency correctness problems. The article “The Invisible traps in Multithreading” describes a series of thread synchronization tools, such as synchronized keyword, ReentrantLock explicit lock, CAS operation, volatile keyword, we believe that with the protection of these tools, we can write a large number of correct multithreading programs.

The efficiency problem

While it is possible to write correctly multithreaded programs using the tools of the Thread-synchronization toolkit, it is not worth the cost if it executes too slowly or even worse than a single-threaded program. So not only do we have to be “right”, but we have to be “fast” if we are “right”. In the Guide to Multithreading Acceleration, we can use techniques such as CAS, ForkJoinPool, thread closure, and the Java.util.Concurrent toolkit to make our multithreaded programs 10, 100, or even 1,000 times faster.

The deadlock problem

Deadlock problems are relatively special because they cause the program to fail to execute at all. It produces no wrong results and is more than just slow because the program stops completely. Deadlocks can be encountered in all kinds of concurrent programs, such as databases, operating systems, and so on. If it was our personal computer, it would be ok to restart after the crash, but online services are often uninterruptible, which requires us to find more and better solutions to solve the deadlock problem in different situations. After reading this article, 100 Ways to Solve Deadlocks, you will have more ideas for this problem.

Multithreaded programming (implementing a blocking queue)

Having covered so many multi-threaded concepts, techniques and tricks, it’s time to practice. Blocking queue is not only an important tool in multithreaded programming, but also uses a series of important knowledge points such as mutex, condition variables, concurrent optimization to implement, which is the best material for us to practice. Let’s follow in the footsteps of “Implementing your Own Blocking Queue from 0 to 1” and go from 0 to 1 to N to complete a complete IMPLEMENTATION of blocking queues at the JDK level.

Advanced topics

After looking at the basics of multithreading, the key techniques, and finally a hands-on experience, we are ready to move on to deeper advanced topics in multithreading.

Thread pool run model source code parsing

In the previous article, we learned how to use thread pools, although thread pools are good stewards, if we don’t understand their temper, we can cross some of their boundaries without realizing it, and finally get thrown to the ground by them. So now let us through the “thread pool running model source code full analysis” to analyze the running model of the thread pool, from the source point of view to understand how the thread pool works.

The underlying implementation of the synchronization mechanism

We have used so many thread synchronization mechanisms that they are amazing and help us avoid one trap after another. So how does all this awesome stuff work? This will please the us behind the hero AbstractQueuedSynchronizer (AQS). Most thread synchronization classes in java.util.Concurrent are implemented based on AQS, Common examples include ReentrantLock, CountDownLatch, ReentrantReadWriteLock, and Semaphore. In The Underlying Implementation of Synchronization, we can take a look at how AQS implements so many different styles of thread synchronization.

conclusion

Here, we have completed the entire Java multithreaded knowledge system journey. In this process, we first understand the basic concept of concurrency and the basic method of Java multithreaded programming, and then appeared the thread pool, an excellent steward for us to take care of all the trouble of task execution and thread scheduling. Then we systematically understand and solve three main problems in multithreading: correctness problem, efficiency problem and deadlock problem. After mastering so much knowledge and skills of Java multithreaded programming, we will implement a blocking queue to a large training, not only can test our multithreaded programming skills, but also deepen our understanding of these knowledge. Finally, we dive into the deep waters of multithreading knowledge, using mature JDK and Netty source code to explore three lower-level advanced topics: event-driven model, thread pool running model, and low-level implementation of synchronization mechanism.