I have to say that in addition to object orientation, the hardest part of the JavaSE phase is multi-threading.

Multithreading seems to be a problem by nature, the entry is difficult to say, and do not see the upper limit of technology. The most crucial thing is that the interview must be tested! Such as Taobao jingdong billions of high concurrency systems have its shadow. In addition, multithreading and the bottom of the system close relationship, not to say non-class players, is the serious four years of C++ people, often in the interview by multithreading a clap dead.

This article will comb through a few small details about multi-threading with you, and try to give “a little easier” answers and concepts, to help non-professional friends better and faster grasp multi-threading learning points.

Content Introduction:

  • Concepts and differences between threads and processes
  • Two common ways to create multiple threads
  • Thread source code
  • Inherit Thread VS implement Runnable

Concepts and differences between threads and processes

process

When we double click the icon on the desktop, the system will load the corresponding program into memory, and the program will occupy a portion of the memory to perform operations. Programs that enter memory are processes (an application can run multiple processes at the same time). When the task manager is used to close the program (such as QQ), the system will remove the program from memory, and the process ends.

A process is a program that occupies a certain amount of memory. The process terminates when the program in memory is cleared.

An application can run multiple processes simultaneously:

thread

A thread is a unit of execution in a process that is responsible for executing a program in the current process. There is at least one thread in a process.

The difference between

A process is the unit of resource allocation and a thread is the unit of execution. Early operating systems had no threads, only processes. However, processes are very “heavy” and inter-process switching costs are high. In order to reduce the cost of process switching caused by concurrency, threading is proposed. A process can have multiple threads. Try to switch between threads, threads have no resources (or very few necessary resources).

Multiple threads preempting CPU execution:

Note that Java itself does not create threads, because threads are actually a resource of the operating system, managed by the operating system. When we say “Java supports multithreading”, we mean that Java can call system resources to create multiple threads.

Single-threaded method call chain (main) :

Enable multi-threading:

Two common ways to create multiple threads

There are two most common ways to create multiple threads in Java (thread pools and Callable next time).

Inherit the Thread class and override the run() method

public class ThreadDemo1 extends Thread {
    public static void main(String[] args) {
        ThreadDemo1 inherits Thread and overwrites run()
        ThreadDemo1 t = new ThreadDemo1();
        // Start thread: the t thread will execute the code in run() once it has the CPU execution authority
        t.start();
    }

    @Override
    public void run(a) {
        System.out.println("Thread is running"); }}Copy the code

Implement the Runnable interface and implement the run() method

public class ThreadDemo2 implements Runnable{
    public static void main(String[] args) {
        ThreadDemo2 implements Runnable and runs ()
        ThreadDemo2 target = new ThreadDemo2();
        // Call the Thread constructor and pass in an instance of TreadDemo2 to create a Thread object
        Thread t = new Thread(target);
        // Start thread: the t thread will execute the code in run() once it has the CPU execution authority
        t.start();
    }

    public void run(a) {
        System.out.println("Thread is running"); }}Copy the code

The above two pieces of code, I believe we are already familiar with the heart, will not repeat. Here is a point to mention: many beginners, when learning multithreading, are repeatedly told that “the actual programming is often only the implementation of the Runnable interface”, over time, they will feel that Thread class is useless, as long as the Runnable interface on the line.

Put the cart before the horse! In fact, Thread class is the most important, it is the core of multithreading.

Thread source code

Runnable defines only one abstract method run() :

Programmatically, this interface is almost useless. The Runnable interface was developed for two purposes:

  • Qualifies the parameter type of the Thread constructor (for approach 2)
  • Extract run() up as an abstract method and let the implementation class override it (why?).

To better understand the above two statements, look at the source code of the Thread class (excerpt) :

public class Thread implements Runnable {
    /* What will be run. */
    private Runnable target;
   
    // constructor
    public Thread(a) {
        init(null.null."Thread-" + nextThreadNum(), 0);
    }
    
    // constructor
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

    @Override
    public void run(a) {
        if(target ! =null) { target.run(); }}}Copy the code

After understanding the above source code, let’s take a fresh look at the two ways Java can create multithreading:

Do you think t.start() calls run() directly after starting the thread? NO! It wants to save the country!

You should now have a better understanding of these two pieces of code that you’re used to. But it’s not enough. We still don’t know what those two sentences mean.

  • “Qualifying the parameter type of the Thread constructor”

In fact, this sentence is for the way to create multiple threads 2 said. Method 2 requires that we pass in a Runnable implementation object when creating Thread instances:

ThreadDemo2 implements Runnable and runs ()
 ThreadDemo2 target = new ThreadDemo2();
 // Call the Thread constructor and pass in an instance of TreadDemo2 to create a Thread object
 Thread t = new Thread(target);
Copy the code

Why pass Runnable implementation objects? Because for approach 2, the code to execute is not in the Thread itself, but in Runnable’s implementation class, you must pass in an object telling the Thread where to execute. The parameter constructor for Thread takes a parameter of type Runnable:

 // constructor
 public Thread(Runnable target) {
     init(null, target, "Thread-" + nextThreadNum(), 0);
 }
Copy the code

So method 2 requires that we write a class that implements Runnable. This is what it means to limit the parameter type of the Thread constructor:

Thread’s argument constructor is only allowed to accept Runnable implementation objects (including Thread subclasses).

Think of the Thread class as a big bucket, but with a tight entry controlled by Runnable. If our class does not implement Runnable, we cannot “plug” threads.

  • Extract run() up as an abstract method, forcing the implementation class to override (why?)

Why extract run up as an abstract method? This is determined by the inheritance of Runnable, Thread, and their respective implementation classes and subclasses:

A closer look reveals the following:

  • A thread always starts with start() because it is the key that opens the thread. Thread run() is automatically called when the Thread is started.
  • The essence of run() is simply to “wrap” blocks of code that need to be executed by threads

When we actually code, all we have to do is write the code in the yellow dotted box, which is to write Thread subclasses or Runnable implementation classes.

Although there may seem to be a lot of runs (), threads that are “woken up” by start() will only call Thread’s run(), which may come from the Thread class (approach 2) or a subclass of Thread (approach 1). In other words, the Thread class (and its subclasses) is the entry point for the Thread to run! Without Thread, Runnable and its implementation classes are decoration.

The Thread class and its subclasses are always the entry point. The code written in the Runnable implementation class can be executed only because Thread’s run() calls target.run().

Inherit Thread VS implement Runnable

As mentioned at the beginning of this article, practical programming often chooses to implement Runnable to create multiple threads. Why is that? There’s a little bit of decoupling in there as well. There is an old saying in programming that “there is no problem that can’t be solved by bringing in a third party.” The way Runnable is implemented is by moving the “executable code” from the thread class to the Runnable implementation class, forcing the “third party” out of the way.

The benefit of implementing Runnable is that the executant is separated from the executee. On the other hand, Thread inheritance is convenient, but the Thread and the code to be run are in the same class, so resources cannot be independent and thus cannot be shared.

Note that Thread inheritance on the left does not share resources, because each subclass object has its own run(), which does not affect each other.

summary

  • Runnable is a functional interface. What it does is

    • To standardize the type of pass that Thread takes parameters
    • Extract run() up as an abstract method and let the implementation class implement it
  • Thread is the lifeblood and entrance of multithreading. Without it, multithreading is impossible. In either case, the entry point is to run() for Thread and then execute the code, but in the second case, it is more convoluted and eventually loops back to run() for the Runnable implementation.

  • Runnable is more commonly implemented because it separates threads from resources. Real programming tends to just write Runnable as an anonymous object, rather than writing another class. Each New Thread inserts a Runnable, so there is no sharing.

way1Thread: Thread: Thread: Thread: Thread: Thread: Thread: Threadnew Thread(){
    @Override
    public void run(a) {
        System.out.println("The code waiting for Thread1"); } }.start(); way2Runnable anonymous object that can only be used once by the current thread.new Thread(new Runnable() {
    public void run(a) {
        System.out.println("The code waiting for Thread2"); } }).start(); way3(Runnable implementation, can be shared by multiple threads) : Runnable r =new Runnable() {
    System.out.println("The code waiting for Threads");
};
Thread t1  = new Thread(r);
Thread t2  = new Thread(r);
Thread t3  = new Thread(r);
Thread t4  = new Thread(r);
Thread t5  = new Thread(r);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
Copy the code

To consider

One last thought, guess what it printed? :

new Thread(new Runnable() {
    public void run(a) {
        System.out.println("Runnable's run method is running"); {}})@Override
    public void run(a) {
        System.out.println("Thread's run method is running");
    }
}.start();
Copy the code

I’m bravo1988. See you next time.

Scot ro si · Feeling the mezzo

Previous articles:

Comics: From JVM locks to Redis distributed locks

What if the company forbids JOIN queries?

Simple Java annotations

Tomcat: Lonely kitten