java multithreading learning notes

Keywords: Java Spring Boot unit testing

1, Introduction to implementation method

There are three ways to create threads in java

The second interface implementation is commonly used, because the way to implement the interface is more flexible than the way to inherit classes, and it can also reduce the coupling between programs.

2, Inherit Thread class

Thread class is the parent class of all thread classes, which implements the extraction and encapsulation of threads
Implementation steps:

  1. Define a class, inherit the Thread class, and override the run method of the class. The run method body is the completed task.
  2. Create an object of Thread class, that is, create a child Thread
  3. Start the thread with the start method of the thread object

Create a ticketing system Demo

package com.example.threaddemo;

//Define a class that inherits the Thread class
public class SellTickets extends Thread{
    private int count = 100;

    //Rewrite the run method of this class. The body of the run method is the completed task.
    @Override
    public void run() {
        while (count > 0){
            count--;
            System.out.println(Thread.currentThread().getName() + "surplus" + count + "Ticket");
        }
    }
}

Writing test classes

package com.example.threaddemo;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ThreadDemoApplicationTests {

    public static void main(String[] args) {
        //Create an object of Thread class, that is, create a child Thread
        SellTickets s1 = new SellTickets();
        SellTickets s2 = new SellTickets();
        SellTickets s3 = new SellTickets();

        //Start the thread with the start method of the thread object
        s1.start();
        s2.start();
        s3.start();
    }

}

result


It indicates that three threads execute separately, with theout sequence

3, Implement Runnable interface

Use the Runnanle interface and start the multithreading step:

  1. Write an implementation class to implement the Runnable interface, and rewrite the run method of the class. The run method body is the completed task.
  2. Create an object of a class that implements the Runnable interface
  3. Use the implementation class object to create a child thread
  4. Call the start method of the thread object to start the thread

The ticket class implements the Runnable interface

package com.example.threaddemo;

//Define a class to implement the Runnable interface
public class SellTickets implements Runnable{
    private int count = 100;

    //Rewrite the run method of this class. The body of the run method is the completed task.
    @Override
    public void run() {
        while (count > 0){
            count--;
            System.out.println(Thread.currentThread().getName() + "surplus" + count + "Ticket");
        }
    }
}

Writing test classes

package com.example.threaddemo;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ThreadDemoApplicationTests {

    public static void main(String[] args) {
        //Create an object of a class that implements the Runnable interface
        SellTickets s = new SellTickets();
        //Creating child threads using objects
        Thread t1 = new Thread(s);
        Thread t2 = new Thread(s);
        Thread t3 = new Thread(s);

        //Start the thread with the start method of the thread object
        t1.start();
        t2.start();
        t3.start();
    }

}

result

4, Comparison of two methods

  • Inherit Thread:

Advantages: simple coding. To access the current thread, in addition to using Thread.currentThread(), you can also use the super keyword
Disadvantages: because java inherits multiple implementations, it cannot inherit other classes if it inherits Thread

  • Implement Runnable

Advantages: multiple implementations, can inherit other classes. Multiple threads can share the same object, which is suitable for processing the same resource.
Disadvantages: it is a little complex. You can only use Thread.currentThread() to access the current thread

5, The difference between the start() and run() methods

  • The start() method creates a new thread and lets the thread execute the run() method.
  • The call to run() can also be executed normally. However, you can't create a new thread. Instead, you call the run() method in the current thread, just as an ordinary method call.

6, Creating threads through Callable and Future

Java provides a Callable interface, which is an enhanced version of the Runnable interface. The Callable interface provides a call() method, which can be regarded as the execution body of a thread, but the call() method is more powerful than the run() method.

  • The call() method can have a return value.
  • The call() method can declare that an exception is thrown.

The steps are as follows:

  1. Create an implementation class of the Callable interface and implement the call() method. The call() method will be used as the execution body of the thread, and the call() method has a return value, and then create an instance of Callable. Starting with Java 8, you can create Callable objects directly using Lamda expressions.
  2. Use the FutureTask class to wrap the Callable object, which encapsulates the return value of the call() method of the Callable object.
  3. Create and start a new Thread using the FutureTask object as the target of the Thread object.
  4. Call the get() method of the FutureTask object to get the return value after the execution of the child thread.

Test class code

package com.example.threaddemo;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

@SpringBootTest
class ThirdThread {

    public static void main(String[] args)
    {
        // Create Callable object
        ThirdThread rt = new ThirdThread();
        // First create a callable < integer > object using a Lambda expression
        // Use FutureTask to wrap Callable objects
        FutureTask<Integer> task = new  FutureTask<Integer>((Callable<Integer>)() -> {
            int i = 0;
            for ( ; i < 100 ; i++ )
            {
                System.out.println(Thread.currentThread().getName()
                        + " Cyclic variable of i Value of:" + i);
            }
            // The call() method can have a return value
            return i;
        });
        for (int i = 0 ; i < 100 ; i++)
        {
            System.out.println(Thread.currentThread().getName()
                    + " Cyclic variable of i Value of:" + i);
            if (i == 20)
            {
                // The essence is to create and start a thread with a Callable object
                new Thread(task , "Thread with return value").start();
            }
        }
        try
        {
            // Get thread return value
            System.out.println("Return value of child thread:" +  task.get());
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }
    
}

result

explain
The program first creates a Callable object using a Lamda expression, and then wraps the instance into a FutureTask object. In the main thread, when the loop variable i is equal to 20, the program starts the thread with the futruetask object as the target. The program finally calls the get() method of the FutrueTask object to return the return value of the call() method. This method will cause the main thread to be blocked until the call() method ends and returns, so the return value of the child thread is always the last output of the call.

7, Non blocking asynchronous programming using completable future

Introduction to completable future

Posted by Zephyr_Pure on Wed, 20 Oct 2021 11:57:26 -0700