Detailed explanation of multithreading

Posted by Prodigal Son on Fri, 11 Feb 2022 09:42:40 +0100

Detailed explanation of multithreading

1, Thread introduction

Processes and threads:

2, Thread Basics

Common method calls and multithreading:

1. Thread creation

There are three ways to create threads:

  1. Thread.class: inherits the thread class.
  2. Runable interface: implements the Runnable interface.
  3. Callable interface: implements the callable interface.

Inherit thread Class implements multithreading (not recommended because it is limited by single inheritance):

  1. Custom Thread class inherits Thread class
  2. Rewrite the run() method and write the thread execution body
  3. Create a thread object and call the start() method to start the thread

Note: the thread does not necessarily execute immediately after starting, but is scheduled by the CPU.

package demo01;


/**
 *
 1.  Thread creation method 1: inherit the thread class, rewrite the run () method, and call start to start the thread
 2.  3.  The thread is scheduled by the CPU, and the summary is not executed immediately.
 4.  */
public class TestThread1 extends Thread{

    @Override
    public void run() {
        // run method thread body
        for (int i = 0; i < 200; i++) {
            System.out.println("I'm looking at the code---"+1);
        }
    }


    public static void main(String[] args){

        /**
         *
         * main Main thread
         *
         * Create a thread object
         */
        TestThread1 testThread1 = new TestThread1();

        //Call the start () method to start the thread.
        testThread1.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("I'm learning multithreading--");
        }
    }
}

The test found that they were executed separately.

Implement the Runnable interface to realize the thread (recommended to avoid the limitation of single inheritance, flexible and convenient, so that the same object can be used by multiple threads):

  1. Define the MyRunnable class to implement the Runnable interface
  2. Implement the run() method and write the thread execution body
  3. Create a thread object and call the start() method to start the thread
package demo01;

/**
 *
 *  Implement the runnable interface and rewrite the run method. The execution thread needs to drop into the runnable interface implementation class and call the start method.
 *
 */
public class TestThread2 implements Runnable {

    @Override
    public void run() {
        // run method thread body
        for (int i = 0; i < 200; i++) {
            System.out.println("I'm looking at the code---"+1);
        }
    }


    public static void main(String[] args){

        /**
         *
         * Create the implementation class object of runnable interface
         *
         * Create a thread object and start our thread agent through the thread object
         */
        TestThread2 testThread2 = new TestThread2();

//        Thread thread = new Thread(testThread2);
//
//        thread.start();

        // Abbreviation
        new Thread(testThread2).start();


        for (int i = 0; i < 1000; i++) {
            System.out.println("I'm learning multithreading--");
        }
    }
}

Multithreading through Callable interface

Introduction to the allable interface:

  1. java.util.concurrent.Callable is a generic interface with only one call() method
  2. The all() method throws an Exception and returns a specified generic class object

The Callable interface implements multithreading application scenarios

  1. When the parent thread wants to get the running results of the child thread

Steps to implement multithreading using Callable interface

  1. Create an instantiated object of a subclass of Callable
  2. Create a FutureTask object and pass the Callable object into the construction method of FutureTask
  3. Instantiate the Thread object and pass in the FurureTask object in the constructor
  4. Start thread

Thread implementation using Callable interface:

package demo01;

import java.util.concurrent.Callable;
public class TestThread4 implements Callable<String> {

    @Override
    public String call() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("=====");
        return "9999";
    }
}
package demo01;

import java.util.concurrent.FutureTask;

public class TestThread5 {
    public static void main(String[] args) {

        FutureTask<String> ft = new FutureTask<>(new TestThread4());
        new Thread(ft).start();
    }
}

Anonymous classes and subclasses implement the Callable interface to create sub threads

package demo01;

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

public class TestThread3 {
    public static void main(String[] args) {

        Callable<String> cl = new Callable<String>() {



            @Override

            public String call() throws Exception {

                System.out.println(Thread.currentThread().getName() + "Marching~~~");

                System.out.println(Thread.currentThread().getName() + "Encounter the enemy~~~");

                System.out.println(Thread.currentThread().getName() + "Kill the enemy bravely!!!!");

                return "The battle was won and 50000 enemy troops were captured";

            }



        };

        FutureTask<String> ft = new FutureTask(cl);

        new Thread(ft, "Li cunxiao troops").start();

        try {

            Thread.currentThread().setName("Li Cunxu troops");

            Thread.sleep(3000);

            System.out.println(Thread.currentThread().getName() + "Rest 3000 ms");

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        System.out.println(Thread.currentThread().getName() + "After rectification, wait for news from friendly forces...");

        try {

            String str = ft.get();

            System.out.println("Li Cunxu's troops learned that the news of the friendly forces was:" + str);

        } catch (InterruptedException | ExecutionException e) {

            e.printStackTrace();

        }

    }
}

2. Thread status

  1. Creation status: Thread t = new Thread() once the thread object is created, it enters the new state.
  2. Ready state: when the start () method is called, the thread immediately enters the ready state, but it does not mean that the execution is scheduled immediately.
  3. Running state: when the thread in the ready state is scheduled by the cpu, the thread enters the running state. At this time, the thread will execute the code of the thread body.
  4. Blocking state: when the sleep, wait or synchronization lock is called, the thread enters the blocking state. After the blocking state contacts, the thread will return to the ready state and wait for the cpu to schedule and execute.
  5. Dead state: the thread is interrupted or terminated. Once it enters the dead state, it cannot be started again.

3. Thread method

4. Thread stop

The stop() and destroy() methods provided by JDK are not recommended (obsolete).
It is recommended that the thread stop by itself. It is recommended to use a flag bit to terminate the variable. When flag = false, the thread is terminated.

Chestnuts:

package state;

/**
 * Test stop
 * 1.It is recommended that the thread be stopped normally -- > utilization times, and dead loop is not recommended
 * 2.It is recommended to use flag bit -- > to set a flag bit
 * 3.Do not use outdated methods such as stop or destroy, or methods that are not recommended by JDK
 */
public class TestStop implements Runnable {
    // 1. Set a flag bit
    private boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println("run...Thread" + i++);
        }
    }

    // 2. Set a public method to stop the thread and convert the flag bit
    public void stop() {
        this.flag = false;
    }

    public static void main(String[] args) {
        TestStop stop = new TestStop();
        new Thread(stop).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("main..." + i);
            if (i == 900) {
                //Call stop() to switch the flag bit and let the thread terminate
                stop.stop();
                System.out.println("The thread stopped");
            }
        }
    }
}

5. Thread hibernation

  • sleep specifies the number of milliseconds that the current thread is blocked;
  • There is an exception InterruptedException in sleep;
  • After the sleep time reaches, the thread enters the ready state;
  • sleep can simulate network delay, countdown, etc;
  • Each object has a lock, and sleep will not release the lock;

6. Comity

  • Comity thread: pause the currently executing thread without blocking;
  • Change the thread from running state to ready state;
  • Let the cpu reschedule, comity is not necessarily successful! kan CPU scheduling;

Chestnuts:

package state;


/**
 * Test comity thread
 * Comity does not necessarily succeed. It depends on your mood
 */
public class TestYield {
    public static void main(String[] args) {
        MyYeild myYeild = new MyYeild();
        new Thread(myYeild, "a").start();
        new Thread(myYeild, "b").start();
    }
}

class MyYeild implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "The thread starts executing");
        Thread.yield();//Comity
        System.out.println(Thread.currentThread().getName() + "Thread stop execution");
    }
}

7. Thread enforcement

Join merge threads. After this thread is executed, other threads are executed, and other threads are blocked. It can be imagined as queue jumping.

Chestnuts:

package state;

/**
 * Test join
 * Jump in line
 */
public class TestJoin implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 500; i++) {
            System.out.println("thread  vip" + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //Start our thread
        TestJoin joinThread = new TestJoin();
        Thread thread = new Thread(joinThread);
        thread.start();

        //Main thread
        for (int i = 0; i < 500; i++) {
            if (i == 200) {
                thread.join();//Jump in line
            }
            System.out.println("main" + i);
        }
    }
}

8. Thread priority


Chestnuts:

package state;

public class ThreadPriority {
    public static void main(String[] args) {
        //Default priority of main thread
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());

        MyPriority myPriority = new MyPriority();
        Thread thread1 = new Thread(myPriority);
        Thread thread2 = new Thread(myPriority);
        Thread thread3 = new Thread(myPriority);
        Thread thread4 = new Thread(myPriority);
        Thread thread5 = new Thread(myPriority);

        //Set priority before starting
        thread1.start();

        thread2.setPriority(1);
        thread2.start();

        thread3.setPriority(4);
        thread3.start();

        thread4.setPriority(Thread.MAX_PRIORITY);//MAX_PRIORITY=10
        thread4.start();

        thread5.setPriority(8);
        thread5.start();
    }
}
class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
}

9. Daemon thread

  • Threads are divided into user threads and daemon threads
  • The virtual machine must ensure that the user thread has completed execution
  • The virtual machine does not have to wait for the daemon thread to finish executing
  • Such as recording operation logs in the background, monitoring memory and garbage collection

Chestnuts:

package state;

public class DaemonThread {public static void main(String[] args) {
    God god = new God();
    You you = new You();

    Thread thread = new Thread(god);
    //The default false indicates that it is a user thread. Normal threads are user threads
    thread.setDaemon(true);
    //God daemon thread start
    thread.start();
    //Your user thread starts
    new Thread(you).start();
}
}

/**
 * lord
 */
class God implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("God bless you");
        }
    }
}

/**
 * you
 */
class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("You live happily all your life");
        }
        System.out.println("====goodbye!world====");
    }
}

3, Thread synchronization

Multiple threads operate on the same resource:

Thread synchronization:


Unsafe thread cases:

Ticket purchase:

package state;

public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new Thread(buyTicket, "Zhang San").start();
        new Thread(buyTicket, "Li Si").start();
        new Thread(buyTicket, "Wang Wu").start();
    }
}

class BuyTicket implements Runnable {
    //ticket
    private int ticketNums = 10;
    boolean flag = true;

    @Override
    public void run() {
        //Buy a ticket
        while (flag) {
            try {
                buy();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //Buy a ticket
    private void buy() {
        //Judge whether there are tickets
        if (ticketNums <= 0) {
            flag = false;
            return;
        }
        //delay
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //Buy a ticket
        System.out.println(Thread.currentThread().getName() + "Get" + ticketNums--);
    }
}

Bank withdrawal:

package state;

public class UnsafeBank {
    public static void main(String[] args) {
        Account account = new Account(100, "Marriage fund");
        Drawing you = new Drawing(account, 50, "Exhibition hall");
        Drawing girlfriend = new Drawing(account, 100, "sad");
        you.start();
        girlfriend.start();
    }
}

//account
class Account {
    int money;//balance
    String cardName;//Card name

    public Account(int money, String cardName) {
        this.money = money;
        this.cardName = cardName;
    }
}

//Bank: simulated withdrawal
class Drawing extends Thread {
    Account account;//account
    int drawingMoney;//Withdrawal amount
    int nowMoney;//The money in your hand

    public Drawing(Account account, int drawingMoney, String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    //Withdraw money
    @Override
    public void run() {
        //Judge whether you have money
        if (account.money - drawingMoney < 0) {
            System.out.println(Thread.currentThread().getName() + "Sorry, your credit is running low,Cannot withdraw money");
            return;
        }
        try {
            Thread.sleep(1000);//Amplify the occurrence of the problem
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Amount in card = balance - your money
        account.money = account.money - drawingMoney;
        //The money in your hand
        nowMoney = nowMoney + drawingMoney;
        System.out.println(account.cardName + "The balance is:" + account.money);
        //this.getName()==Thread.currentThread().getName()
        System.out.println(this.getName() + "Money in hand:" + nowMoney);
    }
}

Thread unsafe collection:

ublic class Demo26_UnsafeList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 1000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        System.out.println(list.size());
    }
}

Synchronization method

Disadvantages:

Synchronization block:

Use synchronized to solve the above cases:

Ticket buying questions:

package state;

public class UnsafeBuyTicket2 {
    public static void main(String[] args) {
        BuyTicket1 buyTicket = new BuyTicket1();
        new Thread(buyTicket, "Zhang San").start();
        new Thread(buyTicket, "Li Si").start();
        new Thread(buyTicket, "Wang Wu").start();
    }
}

class BuyTicket1 implements Runnable {
    //ticket
    private int ticketNums = 10;
    boolean flag = true;

    @Override
    public void run() {
        //Buy a ticket
        while (flag) {
            try {
                buy();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //The synchronized synchronization method locks this
    private synchronized void buy() {
        //Judge whether there are tickets
        if (ticketNums <= 0) {
            flag = false;
            return;
        }
        //delay
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //Buy a ticket
        System.out.println(Thread.currentThread().getName() + "Get" + ticketNums--);
    }
}

Banking issues:

package state;

public class UnsafeBank2 {
    public static void main(String[] args) {
        Account1 account = new Account1(100, "Marriage fund");
        Drawing1 you = new Drawing1(account, 50, "Exhibition hall");
        Drawing1 girlfriend = new Drawing1(account, 100, "sad");
        you.start();
        girlfriend.start();
    }
}

//account
class Account1 {
    int money;//balance
    String cardName;//Card name

    public Account1(int money, String cardName) {
        this.money = money;
        this.cardName = cardName;
    }
}

//Bank: simulated withdrawal
class Drawing1 extends Thread {
    Account1 account;//account
    int drawingMoney;//Withdrawal amount
    int nowMoney;//The money in your hand

    public Drawing1(Account1 account, int drawingMoney, String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    //Withdraw money
    @Override
    public void run() {
        //The object of the lock is the quantity of the variable, which needs to be added, deleted, modified and queried
        synchronized (account) {
            //Judge whether you have money
            if (account.money - drawingMoney < 0) {
                System.out.println(Thread.currentThread().getName() + "Sorry, your credit is running low,Cannot withdraw money");
                return;
            }
            try {
                Thread.sleep(1000);//Amplify the occurrence of the problem
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //Amount in card = balance - your money
            account.money = account.money - drawingMoney;
            //The money in your hand
            nowMoney = nowMoney + drawingMoney;
            System.out.println(account.cardName + "The balance is:" + account.money);
            //this.getName()==Thread.currentThread().getName()
            System.out.println(this.getName() + "Money in hand:" + nowMoney);
        }
    }
}

Set questions:

//Thread safe collection synchronization block
public class Demo29_SafeList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 1000; i++) {
            new Thread(() -> {
                synchronized (list) {
                    list.add(Thread.currentThread().getName());
                }
            }).start();
        }
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

4, Deadlock


How to avoid deadlock:

5, Lock lock


The difference between synchronized and Lock:

Chestnuts:

package state;

import java.util.concurrent.locks.ReentrantLock;

public class TestLock {
    public static void main(String[] args) {
        TestLock2 testLock2 = new TestLock2();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
    }
}


class TestLock2 implements Runnable {

    int ticketNums = 10;
    //Define Lock lock
    private ReentrantLock reentrantLock = new ReentrantLock();


    @Override
    public void run() {

        while (true) {
            try {
                reentrantLock.lock(); //Lock
                if(ticketNums > 0 ){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "Purchased the second" + ticketNums-- + "Ticket");

                } else {
                    break;
                }
            } finally {
                //Unlock
                reentrantLock.unlock();
            }

        }
    }
}

6, Thread communication

Application scenario: problems of producers and consumers

Java provides several methods to solve the communication problem between threads:

Solution:

  1. Concurrent collaboration mode "producer / consumer mode" = = = > management method
    • Producer: module responsible for production data (may be method, object, thread, array)
    • Consumer: the module responsible for processing data (possibly methods, objects, threads, arrays)
    • Buffer: consumers cannot directly use the data of producers. There is a buffer between them

Put the data from the producer into the buffer

//Test producer consumer model -- > pipe process method

//product
public class Product {
    private int id;

    public Product(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

//consumer
public class ConsumerThread extends Thread {

    private SyncContainer syncContainer;

    public ConsumerThread(SyncContainer syncContainer) {
        this.syncContainer = syncContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            Product pop = syncContainer.pop();
            System.out.println("Consumed the second"+ pop.getId() + "Product No");
        }
    }
}


//producer
public class ProviderThread extends Thread {

    //Created buffer
    private SyncContainer syncContainer;

    public ProviderThread(SyncContainer syncContainer) {
        this.syncContainer = syncContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("Produced" + i + "Chicken!");
            syncContainer.push(new Product(i));
        }
    }
}


//container
public class SyncContainer {

    //Container size
    Product[] products = new Product[10];
    //Container counter
    int count = 0;

    //Producers put in products
    public synchronized void push(Product product){
        //If the container is full, wait for the consumer
        //Inform consumers to consume and producers to wait
        if(count == products.length) {
            try {
                this.wait();
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        //If the container is not full, produce the product
        products[count] = product;
        count++;
        //Consumers can be notified of consumption
        this.notifyAll();
    }


    //Consumer products
    public synchronized Product pop(){
        //Determine whether the container is empty
        if(count == 0){
            //Inform the producer of production Consumer waiting
            try {
                this.wait();
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }

        //If you can consume
        count--;
        Product product =  products[count];

        //Inform the producer of production
        this.notifyAll();
        return product;
    }
}


public class Main {

    public static void main(String[] args) {
        SyncContainer container = new SyncContainer();
        new ProviderThread(container).start();
        new ConsumerThread(container).start();
    }
}

  1. Concurrent collaboration mode "producer / consumer mode" = = = > semaphore method
//Products -- > Programs
public class TV {

   //The actors performed and the audience waited
   //The audience watched and the actors waited
   String voice;   //A performance
   boolean flag = true;

   //perform
   public synchronized void play(String voice) {

       if(!flag){
           try {
               this.wait();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }

       System.out.println("The actors performed" + voice);
       //Inform the audience to watch
       this.voice = voice;
       this.notifyAll();
       this.flag = !flag;

   }

   //watch
   public synchronized void watch(){
       if(flag){
           try {
               this.wait();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
       System.out.println("The audience watched" + voice);
       //Inform the actors to perform
       this.notifyAll();
       this.flag = !flag;
   }
}

public class Player extends Thread {
   private TV tv = null;

   public Player(TV tv) {
       this.tv = tv;
   }

   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           tv.play("Performed" + i + "Program No");
       }
   }
}

public class Watcher extends Thread {

   private TV tv = null;

   public Watcher(TV tv) {
       this.tv = tv;
   }

   @Override
   public void run() {
       for (int i = 0; i < 100; i++) {
           tv.watch();
       }
   }
}

//Test the problems of producers and consumers: signal lamp method and sign bit solution
public class Main {

   public static void main(String[] args) {
       TV tv = new TV();
       new Watcher(tv).start();
       new Player(tv).start();

   }
}


Use thread pool:

Topics: Java Back-end