The interviewer asked me: how many ways to create threads? I smiled.

Time:2021-7-7

preface

Multithreading is a must in an interview. Interviewers usually start with simple questions, and then dig out your knowledge step by step.

For example, starting from what a thread is, the difference between a thread and a process, several ways to create a thread, several states of a thread, and so on.

Next, it will naturally lead to thread pool, lock, synchronized and JUC. Then it will lead to AQS, CAS, JMM, JVM and other low-level principles.

In this section, we won’t talk about others. We just say that there are several ways to create threads.

Does it feel very simple? It’s just some of them.

In fact, it’s not. Only when we explain to the interviewer clearly and add our own understanding, can we add points in the interview.

text

Generally speaking, we have the following four ways in common use. Let’s introduce how to use them first. Then, how to answer the interviewer’s questions is more appropriate.

1. Inherit thread class

By inheriting the thread class and rewriting its run method, we can create a thread.

  • First, define a class to inherit the thread class and override the run method.
  • Then create the subclass object and call the start method to start the thread.

2. Implementation of runnable interface

You can also create a thread by implementing runnable and the run method.

  • First, a class is defined to implement the runnable interface and the run method.
  • Then create a runnable implementation class object and pass it into the thread constructor as a target
  • Finally, the start method is invoked to start the thread.

3. Implementation of callable interface, combined with future implementation

  • First, define an implementation class of callable and implement the call method. The call method has a return value.
  • Then, through the construction method of futuretask, the callable implementation class is passed in.
  • Take futuretask as the target of thread class and create thread object.
  • Get the execution result of thread through futuretask’s get method.

4. Creating threads through thread pool

Here, the executors of JDK are used to create thread pool objects.

  • First, define an implementation class of runnable and rewrite the run method.
  • Then create a thread pool with a fixed number of threads.
  • Finally, the thread object is passed in through the execute method of the executorservice object.

How many ways to create threads?

So the problem is, I’ve given four ways to create threads. Do you mean that there are four ways to create threads?

Let’s take a look at an explanation of the thread class in the JDK source code, as shown in the figure below.

There are two ways to create a new thread of execution

There are two ways to create a new thread of execution

The two ways mentioned here correspond to the first two ways we introduced.

However, we will find that both methods will eventually call the thread. Start method, and the start method will eventually call the run method.

The difference is that in the way of implementing the Runnable interface, we call the run method of Thread class. Let’s look at the source code,

In this way, the runnable implementation class object created will be assigned to target, and the run method of target will be run.

Let’s look at the way to inherit the thread class. We also need to call the start method of thread to start the thread. Because the subclass rewrites the run method of thread class, the run method of this subclass is executed.

So, we can also say that. In essence, there is only one way to create threads, which is to construct a thread class (its subclass can also be considered as a thread class).

There are two ways to construct thread class, one is to inherit thread class, the other is to implement runnable interface. It eventually creates an object of the thread class (or its subclass).

Let’s look at the implementation of callable, combining future and futuretask. It can be found that the thread class is constructed by new thread (task).

Finally, in the thread pool, we actually give the task of creating and managing threads to the thread pool. The thread is created through the thread factory class defaultthreadfactory (you can also customize the factory class). Let’s look at the concrete implementation of this factory class.

It will set some default values for threads, such as thread name, thread priority, thread group, whether it is a guard thread, etc. Finally, the thread is created by new thread().

Therefore, to sum up. When answering this question, we can say that there is essentially only one way to create a thread, that is, to construct a thread class。( This conclusion comes from 78 lectures on Java Concurrent Programming (Xu Longxi)

Personal thoughts

However, I would like to raise some questions about this conclusion (if you have different opinions, please leave a message at the end of the article)…

In my opinion, if you want to say that there are one, two, three or four, it’s OK. It’s important to be able to say what you are based on, what they are different from and what they have in common. Make sure the interviewer nods to you..

I think it’s far fetched to say that only constructing thread class is a way to create threads. Because, no matter what means you start from, if you want to create a thread, you must construct the thread class in the end( Including the above methods, and even through reflection, it is also a newinstance in the end.

Then, according to this logic, I can say that no matter what object is created, there is only one way to construct this object class. This conclusion seems a bit too boring, because it is a very correct nonsense.

Taking ArrayList as an example, I ask you how many ways to create an ArrayList. You’ll probably tell me to show off how much you know,

  1. Through the construction method,List list = new ArrayList();
  2. adoptArrays.asList("a", "b");
  3. Through the stream API provided by java8, such asList list = Stream.of("a", "b").collect(Collectors.toList());
  4. Through the third-party jar package of guava,List list3 = Lists.newArrayList("a", "b");

And so on, only the above listed four. Now, I tell you that there is only one way to create an ArrayList, that is, to construct an ArrayList class. Are you crazy.

It’s like asking you how many ways to go from Beijing to Shanghai.

You said you could take a car, a train, a motor car, a high-speed rail and a plane.

That’s not right. Motor cars and high-speed trains belong to trains. Cars and trains belong to cars. Cars and planes belong to means of transportation. So there is only one way, that is, by means of transportation.

That’s not right. I can do without transportation. I can’t walk there. (I can also insert my eyes to transmit, just your skin ~).

The final conclusion is that there is only one way, that is, you can go to Shanghai. What conclusion is this…

So I think it’s not proper to say that there is only one way to create threads.

A good technical paper was almost written into an argumentative paper by me…

Different people have different opinions.

Finally, let’s take a look at a very interesting topic I saw on the Internet.

Interesting topic

Q: if a class implements the runnable interface, it will execute the default run method, then judge that the target is not empty, and finally execute the run method implemented in the runnable interface. If you inherit the thread class, the rewritten run method will be executed. Now I inherit the thread class and implement the runnable interface. What should the following program output?

public class TestThread {
    public static void main(String[] args) {
        new Thread(()-> System.out.println("runnable")){
            @Override
            public void run() {
                System.out.println("Thread run");
            }
        }.start();
    }
}

At first glance, I may be confused. What kind of operation is this.

In fact, if we disassemble the above code, we will know that this is a subclass object that inherits the thread parent class and rewrites the run method of the parent class. Then, in the parent thread, an implementation class of runnable interface is passed into the construction method to implement the run method.

Now that the start method is executed, you must first look for the run method in the subclass. If you find the run method, it will be executed directly. The run method of the parent class will not be executed. Therefore, the result is thread run.

If the subclass does not implement the run method, it will look for the run method in the parent class, and the run method of the parent class will determine whether a runnable is passed (that is, whether the target is empty). Now the target is not empty, so it will execute the target. Run method, that is, print the result: runnable.

So the code above looks complicated, but it’s actually very simple. If we look at the essence through the phenomenon, we will find that it is just to investigate the parent-child inheritance relationship of a class. If a subclass rewrites the method of the parent class, it will give priority to the method rewritten by the subclass.

Combined with thread, if you are not familiar with thread running mechanism, you may be confused.

Recommended Today

Implementation example of go operation etcd

etcdIt is an open-source, distributed key value pair data storage system, which provides shared configuration, service registration and discovery. This paper mainly introduces the installation and use of etcd. Etcdetcd introduction etcdIt is an open source and highly available distributed key value storage system developed with go language, which can be used to configure sharing […]