Detailed explanation of multithreading

Multithreading

The difference between concurrency and parallelism:

Concurrency: a single core CPU handles multiple things at the same time,

Parallelism: multi-core CPU s process multiple things at the same time.

1. Four creation methods of multithreading

  1. Integrated Thread class
  2. Implement the Runable interface
  3. Implement Callable interface
  4. Thread pool creation
Runnable and Callable Differences between
runnable run Method has no return value, callable call Method has a return value
runnable run Method can only throw runtime exceptions, callable call Method can capture exception information

1.1 four creation methods of thread pool

  1. newFixThreadPool
  2. newCachedThreadPool
  3. newScheduledThreadPool
  4. Newthreadpoolexecuted (custom thread pool)
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);

#Parameter description
corePoolSize: Number of core threads
maximumPoolSize: Maximum number of threads
keepAliveTime: survival time 
unit: Survival unit
workQueue: Blocking queue
handler: Reject strategy
## Reject policy: the default is to throw an exception directly
    1. AbortPolicy: Throw exception
    2. CallRunsPolicy:  Only the thread of the caller is used to process the task
    3. DiscurdOldestPlicy: When the queue is full, discard the latest task in the queue to execute the latest task
    4. DisCardPolicy: If the queue is full, it will be discarded without processing

1.2 how to set the maximum number of threads in the custom thread pool

  1. IO intensive: judge the amount of IO consumed in your program (assuming that there are 15 large tasks in your program and IO takes up a lot of resources. Just set the maximum number of threads > 15)
  2. CPU intensive: check how many cores your CPU is. (number of threads obtained in the program: runtime. Getruntime() availableProcessores() )

2. State in thread (6 states)

2.1 six states of threads

  • Freshmen (NEW)
  • Run (RUNNABLE)
  • BLOCKED
  • TIMED_WAITING
  • Waiting
  • Destroyed

2.2 thread state analysis

3. Common methods in threads

methodremarks
setPriority()Set the priority of the thread. 0 = = "10", the higher the priority, the higher the possibility of being executed
sleep()Let the current thread sleep. Each thread has a lock. Sleep will not release the lock
join()Wait for the thread to stop
yiled()Release the CPU time slice, let the thread enter the ready state, and re compete for the CPU time slice
interupt()Interrupt thread
deamon()Daemon thread: (virtual machines don't have to wait for the daemon thread to end)

3.1 what is the difference between sleep and wait methods?

  1. wait is a method of the Object class, and sleep is a static method of the Thread class Thread
  2. wait does not need to catch exceptions, sleep needs to catch exceptions
  3. Wait releases the lock, sleep does not. The wait method requires notify. NotifyAll wakes up. The notify method wakes up a thread randomly.
  4. The call location of wait can only be in the synchronous code block, and sleep can be called anywhere

3.2 what is the difference between the submit() and execute() methods in the thread pool?

  • The received parameters are different
  • sumbit() has a return value, but execute does not
  • submit is convenient for exception processing

4. Locks in multithreading

4.1 Synchronized lock

Analysis of Synchronize lock object:

  • Static method: the static method synchronize locks the Class
  • Instance method: the synchronize lock is the calling object of the method
  • Code block: you can arbitrarily specify whether to lock a Class template or a specific object

4.2 Lock lock

private Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();

4.3 difference between synchronized and Lock

  1. The Java Synchronized keyword is a built-in Java Lock class
  2. Synchronized cannot judge the status of obtaining the lock. Lock can judge whether the lock has been obtained
  3. Synchronized can release the Lock automatically, and the Lock needs to be released manually (no release will cause deadlock)

5. Case analysis of producers and consumers

5.1 Synchronized producer consumer issues

Milk boxes
public class Box {
    //Define a member variable that represents the x-th bottle of milk
    private int milk;

    //Define a member variable to represent the shape of the milk box
    private boolean state = false;

    //Provides operations for storing and obtaining milk
    public synchronized void put(int milk) {
        //If there is milk, wait for consumption
        if(state){
            try{
                wait();//wait for
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        //If there is no milk, produce milk
        this.milk = milk;
        System.out.println("The milkman will"+this.milk+"Put the bottle of milk into the milk box");

        //After production, modify the milk box status
        state = true;

        //Wake up other waiting threads
        notifyAll();
    }

    public synchronized void get(){
        //If there is no milk, wait for production
        if(!state){
            try{
                wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        //If there is milk, consume it
        System.out.println("The user gets the second"+this.milk+"Bottle milk");

        //After consuming milk, modify the milk box status
        state = false;

        //Wake up other waiting threads
        notifyAll();
    }
}

//producer

public class Producer implements Runnable {
    private Box b;


    public Producer(Box b) {
        this.b = b;
    }

    @Override
    public void run() {
        for(int i=1;i<=5;i++){
            b.put(i);//The milkman put milk into the milk box
        }
    }
}

//consumer
public class Customer implements Runnable {
    private Box b;
    public Customer(Box b) {
        this.b = b;
    }

    @Override
    public void run() {
        while (true){
            b.get();//Get milk
        }
    }
}

public class BaS {
    public static void main(String[] args) {
        Box box = new Box();//Milk box

        Producer p = new Producer(box);//Producer object

        Customer c = new Customer(box);//Consumer object

        //Create two thread objects and pass the producer object and consumer object as construction method parameters respectively
        Thread t1 = new Thread(p);
        Thread t2 = new Thread(c);

        //Start thread
        t1.start();
        t2.start();

    }
}

5.2 false wakeup of threads

package com.example.testmodule;

/**
 * Four threads are used to simulate the false wake-up problem
 * A,C Threads are added
 * B,D Threads are reduced
 * wait()Method releases the lock
 * A The thread calls wait() to release the lock. Therefore, the C thread can also get the lock and enter the code block. At this time, Num in A and C = 0; After notifyAll() wakes up,
 * num + + will be performed at the same time, which will cause the quantity not to change as required. num = 2
 * To solve the problem of false wake-up: you need to change the if judgment to the while judgment.
 */

public class test {
    public static void main(String[] args) {
        Box box = new Box();


        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                try {
                    box.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A");
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                try {
                    box.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B");
        Thread thread3 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                try {
                    box.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C");
        Thread thread4 = new Thread(() -> {
            for (int i = 0; i < 50; i++) {
                try {
                    box.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D");
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}

class Box {
    public int num;

    public synchronized void increment() throws InterruptedException {
        if (num != 0) {
        // while (num != 0){
            this.wait();
        }
        System.out.println("put:" + num++ + " have:" + num);
        notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {
        if (num == 0) {
        //while (num == 0){
            this.wait();
        }
        System.out.println("get:" + num-- + " have:" + num);
        notifyAll();
    }
}

# Simulation results
put:0 have:1
get:1 have:0
put:0 have:1
get:1 have:0
get:0 have:-1
get:-1 have:-2
get:-2 have:-3
get:-3 have:-4
get:-4 have:-5
get:-5 have:-6 .......

5.3 Lock producer consumer issues

package com.wddongtt.wddong.manyThread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Box {
    //Define a member variable that represents the x-th bottle of milk
    private int milk;

    //Define a member variable to represent the shape of the milk box
    private boolean state = false;
    
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    //Provides operations for storing and obtaining milk
    public void put(int milk) {
        try {
            lock.lock();
            //If there is milk, wait for consumption
            while(state){
                try{
                    condition.await();//wait for
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            //If there is no milk, produce milk
            this.milk = milk;
            System.out.println("The milkman will"+this.milk+"Put the bottle of milk into the milk box");

            //After production, modify the milk box status
            state = true;

            //Wake up other waiting threads
            condition.signalAll();

        }catch (Exception e){
            e.printStackTrace();
        }finally {

            lock.unlock();
        }
    }

    public void get(){
        try {
            lock.lock();
            //If there is no milk, wait for production
            while(!state){
                try{
                    condition.await();
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
            //If there is milk, consume it
            System.out.println("The user gets the second"+this.milk+"Bottle milk");

            //After consuming milk, modify the milk box status
            state = false;

            //Wake up other waiting threads
            condition.signalAll();

        }catch (Exception e){

        }finally {
            lock.unlock();
        }
    }
}

//producer

class Producer implements Runnable {
    private Box b;


    public Producer(Box b) {
        this.b = b;
    }

    @Override
    public void run() {
        for(int i=1;i<=5;i++){
            b.put(i);//The milkman put milk into the milk box
        }
    }
}

//consumer
class Customer implements Runnable {
    private Box b;
    public Customer(Box b) {
        this.b = b;
    }

    @Override
    public void run() {
        while (true){
            b.get();//Get milk
        }
    }
}

class BaS {
    public static void main(String[] args) {
        Box box = new Box();//Milk boxes

        Producer p = new Producer(box);//Producer object

        Customer c = new Customer(box);//Consumer object

        //Create two thread objects and pass the producer object and consumer object as construction method parameters respectively
        Thread t1 = new Thread(p);
        Thread t2 = new Thread(c);

        //Start thread
        t1.start();
        t2.start();

    }
}


5.4 precise wake-up of Condition in lock

The advantage of LOCK over Synchronize is that LOCK can wake up accurately.

Sleep and wake in LOCK

  • Sleep: await()
  • Wake up: signal(),signalAll()
#Precise notification and wake-up threads
package com.sjmp.demo02PC;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A -> B -> C -> A
 * @description:
 */

public class ConditionDemo {
    public static void main(String[] args) {
        Data3 data3 = new Data3();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data3.printA();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data3.printB();
            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data3.printC();
            }
        },"C").start();
    }
}

class Data3{
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private int num = 1; // 1A 2B 3C

    public void printA(){
        lock.lock();
        try {
            while (num != 1){
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+" Im A ");
            num = 2;
            //Wake up 2
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printB(){
        lock.lock();
        try {
            while (num != 2){
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+" Im B ");
            num = 3;
            //Wake up 3
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printC(){
        lock.lock();
        try {
            while (num != 3){
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+" Im C ");
            num = 1;
            // Wake up 1
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

Keywords: Java Back-end

Added by maxat on Mon, 07 Feb 2022 07:08:27 +0200