Whether you’re a freshman in college or a CRUD with 2-3 years of experience, that means you’ll be asked these questions for at least 3 years. Take the time to get to the bottom of them. The best way to get rid of your fear is to face him, Ollie! (This series is the notes and summary of my learning process, and provides debugging code for everyone to play with)

In this section, the feed

By the end of this section, you will have a clear idea of what concurrent programming is and what the main problems it solves are. And you can do three ways to implement threads yourself. (If you are familiar with this section, you can directly like 👍 to complete this chapter.)

This chapter code download

What are the main problems solved by concurrent programming

I don’t know if you have the same problem as me. Before you really use this knowledge to develop, you will combine the double 11 cases frequently asked in the last two years and think that the high concurrency of double 11 is the product of concurrent programming. What I want to say here is that the high concurrency of the Double 11 case certainly includes the content of concurrent programming, but the concurrent programming is not enough to solve the scenario of double 11. If you want to learn the solution of Double 11, you can learn the knowledge points such as asynchronization – queue and cache.

Due to the large speed difference among COMPUTER CUP-memory-disk, hardware resources can not be fully utilized. Therefore, the problem to be solved by high concurrent programming is to maximize the utilization of hardware resources, so as to achieve the effect of improving program efficiency.

Two, three ways to “create” a thread

Why put “create” in quotes here?

To highlight the

There are usually three ways to create a Thread: to create a Thread, to implement the Runnable interface, or to use Futuretask. However, this statement is not rigorous, after learning this case I believe that you can naturally come to the conclusion that there is only one way to create a Thread is to construct a Thread class.

(1) the Thread

Rewrite the run() method by inheriting the Thread class. Without further ado, get right to the code.

public static class ThreadFirstTime extends Thread {

    @Override
    public void run() {
      while (true) {
        System.out.println(this.getName() + "create Thread success!"); }}} public static void main(String[] args) {ThreadFirstTime ThreadFirstTime = new  ThreadFirstTime(); // Start the Thread threadfirsttime.start () with thread.start (); Thread Thread = new Thread(new ThreadFirstTime())); thread.start(); }Copy the code

You can see that by calling the start method of a new Thread object, our Thread is running:

Thread-0create Thread success!
Thread-0create Thread success!
Thread-0create Thread success!
Copy the code

Note the start method here, which will be further dissected and discussed later

(2) the Runnable

Threads are implemented by implementing the Runnable interface and implementing the run() method. The code is simple. Go straight up

  public static class RunnableFirstTime implements Runnable {

    @Override
    public void run() {
      while (true) {
        System.out.println(Thread.currentThread().getName() + "create Runnable success!"); }} public static void main(String[] args) {// Create a Thread, RunnableFirstTime Thread Thread = new Thread(new RunnableFirstTime()); // Call thread.start() to start a Thread. }Copy the code

Here we see a slight difference in the run() method because of the implementation:

ThreadFirstTime is implemented by inheriting Thread so we can use this directly. As you can see, we use this.getName() to get the name of the current Thread.

RunnableFirstTime implements run() by implementing the Runnable interface, so thread.currentthread () is used to get the currentThread object.

CurrentThread () = currentThread() = currentThread()

The same thing is obvious. We can see that in main we create threads by creating Thread objects, and we use thread.start () to start threads. Does that confirm the assertion that there is only one way to create a Thread and that is by creating a Thread class? Don’t worry, let’s see if Futuretask is the same.

(3) the FutureTask

FutureTask implements an implementation with a return value by implementing the Callable interface and overriding the Call () method. Go straight to the code, and then in three steps explain how FutureTask implements the execution unit of a thread.

public static class CallerTask implements Callable<String> {

    @Override
    public String call() throws Exception {
      return Thread.currentThread().getName() + "create FutureTask success!"; }} public static void main(String[] args) {FutureTask<String> FutureTask = new FutureTask<>(new CallerTask()); New Thread(futureTask).start(); new Thread(futureTask).start(); Try {String result = futuretask.get (); System.out.println(result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }}Copy the code

The first step:

public static class CallerTask implements Callable<String> {

    @Override
    public String call() throws Exception {
      return Thread.currentThread().getName() + "create FutureTask success!"; }}Copy the code

Create a task class that implements a task class by implementing the Callable

interface and overriding the Call () method, analogous to the Runnable interface. But the difference between the two is that the Runnable interface implements run() as a void method, whereas Callable

implements call() as you can see in the example given is that it returns a String, a method that returns a value.

The second step:

FutureTask<String> FutureTask = new FutureTask<>(new CallerTask());Copy the code

Use FutureTask’s parameterized constructor to create asynchronous tasks that Thread can manage.

Step 3: Create a Thread manually using new Thread(), and call thread.start () to start the Thread, just like the previous two methods.

New Thread(futureTask).start(); new Thread(futureTask).start(); Try {String result = futuretask.get (); System.out.println(result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }Copy the code

At this point we can clearly see that threads are implemented through FutureTask, which is also created through new Thread(). So at this point I’m sure you all understand that there is only one way to create a Thread and that is to construct a Thread class, and there are three ways to implement it.

Don’t ask questions about how threads are created

How does new Thread() wear three?

Let’s see what this method really is

/**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, target, gname)}, where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     *
     * @param  target
     *         the object whose {@code run} method is invoked when this thread
     *         is started. If {@code null}, this classes {@code run} method does
     *         nothing.
     */
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
Copy the code

This method is a Runnable target.

At this point, place the cursor at the declaration of the current class, which is line 140

public class Thread implements Runnable 
Copy the code

The Thread class implements the Runanble interface. It’s okay to be Runnable. After all, he’s the boss.

We can also guess that FutureTask must implement the Runnable interface

public class FutureTask<V> implements RunnableFuture<V> 

public interface RunnableFuture<V> extends Runnable, Future<V> 
Copy the code

Tracing back to the underlying relationship of the class, we can see that FutureTask implements RunnableFuture, which inherits Runnable and Future.

Some friends may want to ask, Java is not a single inheritance, more implementation? Why is it multiple inheritance? It is important to note that interfaces can be multiple inherited.

Another neat thing to do here is to choose inheritance over implementing Runnable because

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's * run method to be called in that separately executing * thread. * 

* The general contract of the method run is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }

Copy the code

public abstract void run(); If RunnableFuture implements implements, our FutureTask must implement the run() method, which conflicts with our call() method. So choosing to override run() in RunnableFuture will not be required to implement the run() method in subsequent implementation classes.

It’s a little convoluted here, but I want you to read the code twice, because it’s a little bit of detail. Once we understand this relationship, we can see that FutureTask can be created using either Callable or Runnable. In plain English, FutureTask supports both run() and call().

 FutureTask<String> futureTask = new FutureTask<>(new CallerTask());
 
 FutureTask<String> futureTask = new FutureTask(new RunnableFirstTime(),"create FutureTask success!");
Copy the code

Those who are interested in the relationship can follow up with this code and the corresponding description:

    /**
     * Creates a {@code FutureTask} that will, upon running, execute the
     * given {@code Runnable}, and arrange that {@code get} will return the
     * given result on successful completion.
     *
     * @param runnable the runnable task
     * @param result the result to return on successful completion. If
     * you don't need a particular result, consider using * constructions of the form: * {@code Future
       f = new FutureTask
      
       (runnable, null)} * @throws NullPointerException if the runnable is null */ public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW; // ensure visibility of callable }
      Copy the code

We can see that FutureTask can achieve the same effect as Runnable, but we don’t usually play with it that way. In general, the CAL () method of FutureTask is used for this class. If there is no return parameter, we recommend calling the Runnable interface.

Be sure to like 👍 and follow along with me as we continue to learn more