How dare you say you don't understand Java multithreading

Process and thread

concept

Process: a process is an execution process of a program. It is the basic unit for allocating and managing resources during program execution. Each process has its own memory space.

Thread: thread is the basic unit of CPU resource scheduling and allocation. It can share process resources with other threads in the same process.

contact

A thread is a part of a process. A process can have multiple threads, but a thread can only exist in one process.

difference

Fundamental difference: process is the basic unit of operating system resource scheduling, and thread is the basic unit of execution scheduling.
Overhead: the process switching overhead is large, and the thread switching overhead is small.
Sharing: a process has its own independent address space and resources, and threads share the resources of its own process.

Implementation of Java multithreading

Inherit Thread class

package com.Thread.create;

//Inherit the Thread class and override the run() method
class MyThread extends Thread{

    @Override
    public void run() {
        for (int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

public class ThreadDemo_one {

    public static void main(String[] args) {

        //Create a thread and execute
        Thread my_thread = new MyThread();
        my_thread.start();

        //Execution of main thread
        for (int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+ ":" + i);
        }
    }

}

Implement Runnable interface

package com.Thread.create;

//Implement the Runnable interface and rewrite the run() method
class My_Runnable implements Runnable{

    @Override
    public void run() {
        for (int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

public class ThreadDemo_two {

    public static void main(String[] args) {

        //Create a thread and execute
        //1. Create Runnable object
        My_Runnable me = new My_Runnable();
        //2. Pass the Runnable object to the Thread class
        Thread t = new Thread(me);
        //3. Open thread
        t.start();

        //Execution of main thread
        for (int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+ ":" + i);
        }
    }
}

Implement Callable interface

package com.Thread.create;

//Implement the Callable interface and override the call() method

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

class My_Callable implements Callable{

    @Override
    public Object call() throws Exception {
        for (int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
        return null;
    }
}

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

        //Create a thread and execute
        //Create Callable object
        Callable my_callable = new My_Callable();
        //Wrap the Callable object with the FutureTask class
        FutureTask my_task = new FutureTask(my_callable);
        //Pass FutureTask to the Thread class
        Thread t = new Thread(my_task);
        t.start();

        //Execution of main thread
        for (int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+ ":" + i);
        }
    }
}

Use thread pool

package com.Thread.create;

//Use thread pool

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class My_runnable implements Runnable{

    @Override
    public void run() {
        for (int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

public class ThreadDemp_four {

    public static void main(String[] args) {

        //Create thread pool
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        //Create Runnable object
        Runnable me = new My_runnable();
        //Get the thread object from the thread pool and pass the Runnable object
        executorService.submit(me);
        //Close the thread pool. The production environment is irrelevant
        executorService.shutdown();

        //Execution of main thread
        for (int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+ ":" + i);
        }
    }

}

Comparison of advantages and disadvantages of four creation methods

Advantages of implementing Runnable interface over inheriting Thread class:
1. It avoids the limitation of Java single inheritance
2. It is suitable for multiple same program codes to share the same resource
3. Only threads that implement Runnable or Callable classes can be placed in the Thread pool, not inherited Thread classes

Compared with Runnable, Callable:
The main difference is that the call() method has a return value, while the run() method does not

Benefits of using thread pools:
1. Improve response speed and reduce thread creation time
2. Reduce resource consumption and reuse threads in the thread pool
3. It is convenient for thread management. The number of work line threads in the thread pool can be adjusted according to the bearing capacity of the system to prevent the server from getting tired due to excessive memory consumption

Thread synchronization (thread safety)

Thread safety

The so-called thread safety is that multiple threads run at the same time, and these threads may run this piece of code at the same time. Each time the program runs, the result is the same as that of a single thread, and the value of the variable is the same as expected.

Thread safety problems occur when multiple threads access shared resources

Thread synchronization

The use of synchronized mechanism can solve the thread safety problem of multiple threads accessing the same resource

The following ticket buying classes are thread unsafe classes

package com.Thread.synchronize;

public class Sell_Ticket implements Runnable{

    int ticket = 100;
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(ticket>0){
                System.out.println(Thread.currentThread().getName()+"-->Selling the third"+ticket+"Ticket");
                ticket--;
            }
        }
    }
}

Synchronous code block

synchronized(Synchronous lock){
        Code that requires synchronization
}
Synchronous lock:
1,Can be any object
2,Multiple thread objects need to use the same lock
package com.Thread.synchronize;

//Using synchronous code blocks to realize thread safety
/*
synchronized(Synchronous lock){
        Code that requires synchronization
}
Synchronous lock:
1,Can be any object
2,Multiple thread objects need to use the same lock
*/

public class Sell_Ticket_Synchronized_one implements Runnable{

    private int ticket = 100;
    //Create a lock object
    Object obj = new Object();
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (obj){
                if(ticket>0){
                    System.out.println(Thread.currentThread().getName()+"-->Selling the third"+ticket+"Ticket");
                    ticket--;
                }
            }
        }
    }
}

Synchronization method

public synchronized void method(){
	Code that may cause thread safety problems
}

Who is the sync lock?
For non static method,Synchronous lock is this. 
about static method,We use the bytecode object of the class where the current method is located(Class name.class). 
package com.Thread.synchronize;

//Using synchronization method to realize thread safety
/*
The lock object of the synchronization method is its own this
 */


public class Sell_Ticket_Synchronized_two implements Runnable{

    private int ticket = 100;
    @Override
    public void run() {
        while (true){
            sell_ticket();
        }
    }

    private synchronized void sell_ticket(){
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if(ticket>0){
            System.out.println(Thread.currentThread().getName()+"-->Is selling"+ticket+"Ticket");
            ticket--;
        }

    }
}

Lock lock

java.util.concurrent.locks.Lock The mechanism provides better performance than synchronized Code blocks and synchronized Method for a wider range of locking operations,Synchronous code block/Functions of synchronization method Lock Both,In addition, it is more powerful,More object-oriented.

Lock Lock is also called synchronous lock. The locking and releasing methods are as follows:
public void lock() :Add synchronous lock.
public void unlock() :Release the synchronization lock.
package com.Thread.synchronize;

//Using lock object to realize thread safety

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

public class Sell_Ticket_Synchronized_three implements Runnable{

    private int ticket = 100;
    //Create lock object
    Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            //Lock
            lock.lock();
            try {
                Thread.sleep(10);
                if(ticket>0){
                    System.out.println(Thread.currentThread().getName()+"-->Selling the third"+ticket+"Ticket");
                    ticket--;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                //Release lock
                lock.unlock();
            }
        }
    }

}

Thread communication (producer and consumer)

Thread communication

concept

Multiple threads are processing the same resource, but the processing actions (tasks of threads) are different.

For example, thread A is used to generate steamed stuffed buns and thread B is used to eat steamed stuffed buns. Steamed stuffed buns can be understood as the same resource. The actions processed by thread A and thread B are production and consumption, so there is A thread communication problem between thread A and thread B.

Why handle thread communication

When multiple threads execute concurrently, by default, the CPU switches threads randomly. When we need multiple threads to complete a task together, and we want them to execute regularly, some coordinated communication is needed between multiple threads to help us operate a piece of data together.

To sum up, we want threads to execute regularly

How to communicate

Use the wake-up waiting mechanism

Wait for wake-up mechanism

What is waiting to wake up

This is a collaboration mechanism between multiple threads. When it comes to threads, we often think of the race between threads, such as competing for locks, but this is not the whole story. There will also be a cooperation mechanism between threads. Just like you and your colleagues in the company, you may have competition for promotion, but more often you work together to complete certain tasks.

That is, after a thread has performed the specified operation, it enters the waiting state (wait()) and wakes up after other threads have executed their specified code (notify()); When there are multiple threads waiting, you can use notifyAll() to wake up all waiting threads if necessary.

wait/notify is a cooperative mechanism between threads.

Method of waiting for wake-up

1. Wait: the thread is no longer active, no longer participates in scheduling, and enters the wait set. Therefore, CPU resources will not be wasted, nor will it compete for locks. At this time, the thread state is WAITING. It also waits for other threads to perform a special action, that is, to "notify" the threads WAITING on this object to be released from the wait set and re-enter the ready queue
2. notify: select a thread in the wait set of the notified object to release; For example, when a restaurant has a free seat, the customer waiting for the longest meal takes the first seat.
3. notifyAll: release all threads on the wait set of the notified object.

Details of calling wait and notify methods
1. The wait method and notify method must be called by the same lock object. Because: the corresponding lock object can wake up the thread after using the wait method called by the same lock object through notify.
2. The wait method and notify method are methods belonging to the Object class. Because: the lock Object can be any Object, and the class of any Object inherits the Object class.
3. The wait method and notify method must be used in the synchronization code block or synchronization function. Because: these two methods must be called through the lock object.

Producer consumer model

The waiting wake-up mechanism is actually a classic problem of "producers and consumers".

Take the production of steamed stuffed buns and the consumption of steamed stuffed buns as an example. How can the waiting wake-up mechanism make effective use of resources

Baozi shop thread produces baozi, and eating thread consumes baozi. When there is no steamed stuffed bun (the status of steamed stuffed bun is false),The eating thread waits, and the baozi shop thread produces baozi (that is, the baozi status is true),And notify the eating thread (release the waiting state of eating),Because there are already steamed stuffed buns, the steamed stuffed buns shop thread enters the waiting state. Next, whether the eating thread can further execute depends on the acquisition of the lock. If the lock is obtained, the action of eating steamed stuffed buns is executed, and the steamed stuffed buns are finished (the status of steamed stuffed buns is false),And notify the thread of the package store (release the waiting state of the package store),The eating thread is waiting. Whether the package shop thread can execute further depends on the acquisition of the lock.

code implementation

Steamed stuffed bun

package com.Thread.communication;

//Steamed stuffed bun, also known as resource class
public class BaoZi {
    //Steamed stuffed bun skin
    String pi;
    //Steamed stuffed bun stuffing
    String xian;
    //The status of the package, indicating whether the resource exists
    boolean flag = false;
}

Class for producing steamed stuffed bun

package com.Thread.communication;

//A steamed stuffed bun shop means a producer who produces steamed stuffed buns
public class BaoZi_Producer extends Thread{

    private BaoZi baozi;

    public BaoZi_Producer(BaoZi baozi){
        this.baozi = baozi;
    }

    @Override
    public void run() {
        int count = 0;
        //Keep producing and use the while(true) loop
        while (true){
            synchronized (baozi){
                if (baozi.flag == true){
                    try {
                        baozi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //Increase interest
                if (count%2==0){
                    baozi.pi = "Thin skin";
                    baozi.xian = "Beef stuffing";
                    System.out.println("Steamed buns shop produces steamed buns-->"+baozi.pi+baozi.xian+"steamed stuffed bun");
                }else{
                    baozi.pi = "Crispy";
                    baozi.xian = "Pork stuffing";
                    System.out.println("Steamed buns shop produces steamed buns-->"+baozi.pi+baozi.xian+"steamed stuffed bun");
                }
                //It takes five seconds to make a steamed stuffed bun
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count++;
                baozi.flag = true;
                baozi.notify();
            }
        }
    }
}

Steamed stuffed bun eating class

package com.Thread.communication;

//Steamed stuffed bun consumers
public class BaoZi_Comsumer extends Thread{

    private BaoZi baozi;

    public BaoZi_Comsumer(BaoZi baozi){
        this.baozi = baozi;
    }

    @Override
    public void run() {
        while (true){
            synchronized (baozi){

                if (baozi.flag==false){
                    try {
                        baozi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("Eat steamed stuffed bun-->"+baozi.pi+baozi.xian+"steamed stuffed bun");
                //Eat steamed stuffed bun for 3 seconds
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                baozi.flag = false;
                baozi.notify();
                System.out.println("----------------------------------");
            }
        }
    }
}

Test class

package com.Thread.communication;

public class Test {

    public static void main(String[] args) {
        BaoZi baozi = new BaoZi();
        BaoZi_Producer bp = new BaoZi_Producer(baozi);
        BaoZi_Comsumer bc = new BaoZi_Comsumer(baozi);
        bp.start();
        bc.start();
    }
}

Keywords: Multithreading

Added by Warptweet on Mon, 24 Jan 2022 22:24:44 +0200