Of Java core class library (multithreading: realizing multithreading and thread synchronization)

(I) Fundamentals of Java language
(II) Java object oriented programming
(III) Of Java core class libraries (common API s, string classes, collection classes, generics)
(IV) Of Java core class library (exception)
(5) Stay longer.... Continuous updating

1 multithreading

1.1 process

  • Process: is a running program
    • It is an independent unit for the system to allocate and call resources
    • Each process has its own memory space and system resources
  • Three characteristics of process
    • Independence: processes are independent of each other and have their own independent memory areas
    • Dynamic: a process is a running program that dynamically occupies memory, CPU, network and other resources
    • Concurrency: the CPU will poll and switch time-sharing to serve each process in turn. Because the switching speed is very fast, it gives us the feeling that it is executing at the same time. This is concurrency (Concurrency: multiple processes are executing at the same time)

1.2 threads

  • Thread: it is a single sequential control flow in a process and an execution path
    • Single thread: a process has only one execution path
    • Multithreading: a process has multiple execution paths

1.3 implementation of multithreading

1.3.1 method 1: inherit the tree class

  • technological process:

    • 1. Define a myThread class that inherits the tree class
    • 2. Override the run() method in the myThread class
    • 3. Create an object of the myThread class
    • 4. Start thread: void start()
  • Why override the run() method?

    • Because run() is used to encapsulate the code executed by the thread
  • What is the difference between the run() method and the start() method?

    • run(): encapsulates the code executed by the thread. It is called directly, which is equivalent to the call of ordinary methods
    • start(): starts the thread, and then the JVM calls the run() method in the thread
  • example

  • MyThread class:

package test;

//1. Define a class of MyTread inheritance tree class
public class MyThread extends Thread{
    2,stay MyTread Override in class run()method
    @Override
    public void run() {
        for(int i=0;i<100;i++) {
            System.out.println(i);
        }
    }
}
  • Test class
package test;

public class Demo {
    public static void main(String[] args) {
        //3. Create an object of the myThread class
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

        //4. Start thread: void start(): starts the thread, and the Java virtual machine calls the run() method of this thread
        my1.start();
        my2.start();
    }
}

1.3.2 mode 2: implement Runnable interface

  • technological process:
    • 1. Define a MyRunnable class to implement the Runnable interface
    • 2. Override the run() method in the MyRunnable class
    • 3. Create an object of the MyRunnable class
    • 4. Create the object of the tree class and take the MyRunnable object as the parameter of the construction method
    • 5. Start thread
  • Benefits:
    • It avoids the limitation of Java single inheritance
    • It is suitable for multiple code of the same program to process the same resource, and effectively separates the thread from the program code and data, which better reflects the object-oriented design theory
package test;

public class Demo {
    public static void main(String[] args) {
        //3. Create an object of the MyRunnable class
        MyRunnable mr = new MyRunnable();

        //4. Create the object of the tree class and take the MyRunnable object as the parameter of the construction method
//        Thread t1 = new Thread(mr);
//        Thread t2 = new Thread(mr);
        //Thread(Runnable target,String name)
        Thread t1 = new Thread(mr,"high-speed rail");
        Thread t2 = new Thread(mr,"aircraft");

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

1.3.3 mode 3: implement Callable interface

1.4 setting and obtaining thread name

  • Method for setting and getting Thread name in Thread class
Method nameexplain
void setName(Stringname)Change the name of this thread to equal the parameter name
String getName()Returns the name of this thread
public Thread(String name)The thread name can also be set through the construction method
public static Thread currentThread()Returns a reference to the thread object currently executing (you can return the thread in the main() method)
public static void sleep(long time)How many milliseconds does the current thread sleep before continuing execution
  • MyThread class
package test;


public class MyThread extends Thread{
    //Add thread name to constructor
    public MyThread(){}
    public MyThread(String name) {
        super(name);
    }
    
    @Override
    public void run() {
        for(int i=0;i<100;i++) {
            //1,String getName()  	 Returns the name of this thread
            System.out.println(getName()+":"+i);
        }
    }
}
  • Test class
package test;

public class Demo {
    public static void main(String[] args) {
        
/*        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

        //2,void setName(Stringname) 	Change the name of this thread to equal the parameter name
        my1.setName("High speed railway (HSR) ";
        my2.setName("Aircraft ");*/
        
        //3. Set the thread name through the construction method
        //You need to provide this parameter construction method in your own defined class, and access the parent class parameter construction method through super
        /*MyThread my1 = new MyThread("High speed railway (HSR) ";
        MyThread my2 = new MyThread("Aircraft "); 

        my1.start();
        my2.start();*/
        
        //4,public static Thread currentThread()  	 Returns a reference to the thread object currently executing (you can return the thread in the main() method)
        System.out.println(Tread.currentThread().getName()); //main
    }
}

1.5 thread scheduling

  • Threads have two scheduling models

    • Time sharing scheduling model: all threads use the right to use the CPU in turn, and evenly allocate the time slice of CPU occupied by each thread
    • Preemptive scheduling model: give priority to the threads with high priority to use CPU. If the threads have the same priority, one will be selected randomly. The threads with high priority will obtain more CPU time slices
  • Java uses a preemptive scheduling model

  • If the computer has only one CPU, then the CPU can only execute instructions at a certain time. Only when the thread gets the CPU time slice, that is, the right to use, can it execute instructions. Therefore, the execution of multithreaded programs is random, because it is not certain who grabs the right to use the CPU

  • Method for setting and obtaining Thread priority in Thread class

Method nameexplain
public final int getPriority() [praɪˈɔːrəti]Returns the priority of this thread
public final void setPriority(int newPriority)Change the priority of this thread
  • The default priority of thread is 5; The thread priority range is 1-10
  • High thread priority only means that the thread has a high probability of obtaining CPU time, but you can only see the effect you want when it runs more times or more times
package test;

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

        ThreadPriority tp1 = new ThreadPriority();
        ThreadPriority tp2 = new ThreadPriority();
        ThreadPriority tp3 = new ThreadPriority();


        tp1.setName("high-speed rail");
        tp2.setName("aircraft");
        tp3.setName("automobile");

        //1,public final int getPriority() [pra ɪˈɔː r ə ti]  	 Returns the priority of this thread
//        System.out.println(tp1.getPriority()); //5
//        System.out.println(tp2.getPriority()); //5
//        System.out.println(tp3.getPriority()); //5

        //2,public final void setPriority(int newPriority)  	 Change the priority of this thread
        System.out.println(Thread.MAX_PRIORITY); //10
        System.out.println(Thread.MIN_PRIORITY); //1
        System.out.println(Thread.NORM_PRIORITY); //5

        //Set correct priority
        tp1.setPriority(5);
        tp2.setPriority(10);
        tp3.setPriority(1);

        tp1.start();
        tp2.start();
        tp3.start();
    }
}

1.6 thread control

Method nameexplain
static void sleep(long millis)Causes the currently executing thread to stay (pause execution) for the specified number of milliseconds
void join()Wait for this thread to die
void setDaemon(boolean on) [ˈdiːmən]Mark this thread as a daemon. When all running threads are daemon threads, the Java virtual machine will exit soon (not immediately)

Case: sleep() method

  • Thread class
package test;

public class ThreadSleep extends Thread{
    @Override
    public void run() {
        for(int i=0;i<10;i++) {
            System.out.println(getName()+":"+i);
            //1,static void sleep(long millis)  	 Causes the currently executing thread to stay (pause execution) for the specified number of milliseconds
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • Test class
package test;

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

        ThreadSleep ts1 = new ThreadSleep();
        ThreadSleep ts2 = new ThreadSleep();
        ThreadSleep ts3 = new ThreadSleep();


        ts1.setName("Cao Cao");
        ts2.setName("Liu Bei");
        ts3.setName("Sun Quan");


        ts1.start();
        ts2.start();
        ts3.start();

//        Cao Cao: 0
//        Sun Quan: 0
//        Liu Bei: 0
//        Sun Quan: 1
//        Cao Cao: 1
//        Liu Bei: 1
//        ...
    }
}

Case: join() method

package test;

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

        ThreadJoin tj1 = new ThreadJoin();
        ThreadJoin tj2 = new ThreadJoin();
        ThreadJoin tj3 = new ThreadJoin();

        tj1.setName("Kangxi");
        tj2.setName("Four elder brother");
        tj3.setName("Eight elder brother");

        tj1.start();
        //2,void join()  	 Wait for this thread to die
        try {
            tj1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        tj2.start();
        tj3.start();

//        Kangxi: 0
//        Kangxi: 1
//        Kangxi: 2
//        Fourth brother: 0
//        Four elder brothers: 1
//        Eight elder brother: 0
//        Eight elder brother: 1
//        Eight elder brother: 2
//        IV. elder brother: 2
//        ...
    }
}

Case: setDaemon() method

package test;

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

        ThreadJoin tj1 = new ThreadJoin();
        ThreadJoin tj2 = new ThreadJoin();
        ThreadJoin tj3 = new ThreadJoin();

        tj2.setName("Guan Yu");
        tj3.setName("Fei Zhang");
        //Set the main thread to Liu Bei
        Thread.currentThread().setName("Liu Bei");

        //3,void setDaemon(boolean on)  	 Mark this thread as a daemon thread. When all running threads are daemon threads, the Java virtual machine will exit
        tj1.setDaemon(true);
        tj2.setDaemon(true);

        tj1.start();
        tj2.start();

        for(int i=0;i<2;i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
        //After Liu Bei's execution, Guan Yu and Zhang Fei will end soon
    }
}

1.7 thread life cycle

1.8 case of data security: buying tickets


  • Why is there a problem? (this is also the standard for us to judge whether there will be data security problems in multithreaded programs.)

    • Is it a multithreaded environment
    • Is there shared data
    • Are there multiple statements that operate on shared data
  • How to solve the problem of multithreading security?

  • Basic idea: let the program have no security environment

  • How?

    • Lock the code for multiple statements to operate the shared data, so that only one thread can execute at any time
    • Java provides a way to synchronize code blocks

1.9 thread synchronization_ Synchronous code block

  • Locking multiple statements to operate on shared data can be implemented using synchronous code blocks
  • format
synchronized(Any object) {
	Code for multiple statements to operate on shared data
}	
  • Benefits: multiple threads can access shared resources successively, which solves the data security problem of multiple threads

  • Disadvantages: when there are many threads, each thread will judge the lock on synchronization, which is very resource consuming and virtually reduces the running efficiency of the program

  • sellTicket class

package test;

//1. Define a class SellTicket to implement the Runnable interface, which defines a member variable: private int tickets= 100;
public class SellTicket implements Runnable{
    private int tickets = 100;
    private Object obj = new Object();

    //2. Rewrite the run0 method in the ellTicket class to sell tickets. The code steps are as follows
    @Override
    public void run() {
        while(true) {
            //tickes=100
            //t1,t2,t3
            //Suppose t1 grabs the CPU actuator
            synchronized (obj){
                //t1 came in and locked the code
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                        //t1 rest 100ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //Window 1 is selling ticket 100
                    System.out.println(Thread.currentThread().getName() + "The second is being sold" + tickets + "Ticket");
                    tickets--; //tickets=99
                }
                //When t1 came out, the lock was released
            }
        }
    }
}
  • Test class
package test;

public class SellTicketDemo {
    public static void main(String[] args) {
        //Create an object of SellTicket class
        SellTicket st = new SellTicket();

        //Create three Thread class objects, take the SellTicket object as the parameter of the construction method, and give the corresponding window name
        Thread t1 = new Thread(st,"Window 1");
        Thread t2 = new Thread(st,"Window 2");
        Thread t3 = new Thread(st,"Window 3");

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

    }
}

1.10 thread synchronization_ Synchronization method

  • Function: lock the core methods with thread safety problems. Only one thread can access them at a time, and other threads must wait outside the methods
  • Synchronization method: add the synchronized keyword to the method; Lock object: this
    • Format: modifier synchronized return value type method name (method parameter) {}
  • Synchronous static method: add the synchronized keyword to the static method; Lock object: class name class
    • Format: modifier static synchronized return value type method name (method parameter) {}
package test;

public class SellTicket implements Runnable{
//1. Non static private int tickets = 100;
    private static int tickets = 100;
    private Object obj = new Object();
    private int x = 0;

    @Override
    public void run() {
        while(true) {
            if(x%2==0) {
//1 non static synchronized (this){
                synchronized (SellTicket.class) {
                    if (tickets > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "The second is being sold" + tickets + "Ticket");
                        tickets--; //tickets=99
                    }
                }
            } else {
//                synchronized (obj) {
//                    if (tickets > 0) {
//                        try {
//                            Thread.sleep(100);
//                        } catch (InterruptedException e) {
//                            e.printStackTrace();
//                        }
//                        System.out.println(Thread.currentThread().getName() + "selling" + tickets + "ticket");
//                        tickets--; //tickets=99
//                    }
//                }
                sellTicket();
            }
            x++;
        }
    }
//1 non static
//    private synchronized void sellTicket() {
//        if (tickets > 0) {
//            try {
//                Thread.sleep(100);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName() + "selling" + tickets + "ticket");
//            tickets--; //tickets=99
//        }
//    }

    private static synchronized void sellTicket() {
        if (tickets > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "The second is being sold" + tickets + "Ticket");
            tickets--; //tickets=99
        }
    }
}

1.11 thread safe classes (understand)

The methods in the source code are modified by synchronized

StringBuffer

  • Thread safe, variable character sequence
  • Starting from version JDK 5, it is replaced by StringBuilder. The StringBuilder class should usually be used because it supports all the same operations, but it is faster because it does not perform synchronization

Vector

  • From Java 2 platform v1 2, this class improved the List interface to become a member of the Java Collections Framework. Unlike the new collection implementation, the Vector is synchronized. If a thread safe implementation is not required, it is recommended to use ArrayList instead of Vector

Hashtable

  • This class implements a hash table that maps keys to values. Any non null object can be used as a key or value
  • From Java 2 platform v1 2, the class was improved to implement the Map interface and make it a member of the Java Collections Framework. Unlike the new collection implementation, hashtables are synchronized. If thread safe implementation is not required, it is recommended to use HashMap instead of Hashtable

Static < T > List < T > snsynchronizedlist (list < T > list) in the Collections class: returns a list of synchronization (thread safe) supported by the specified list

package test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

public class Demo {
    public static void main(String[] args)  {
        //Static < T > List < T > snsynchronizedlist (list < T > list): returns a list of synchronization (thread safety) supported by the specified list
        Collection<String> list = Collections.synchronizedList(new ArrayList<String>());

        /*The source code returns Synchronized
        public static <T> List<T> synchronizedList(List<T> list) {
            return (list instanceof RandomAccess ?
                    new Collections.SynchronizedRandomAccessList<>(list) :
                    new Collections.SynchronizedList<>(list));
        }*/

    }
}

1.12 Lock lock

  • Lock is an interface that cannot be instantiated directly. The implementation class ReentrantLock is used for instantiation (after JDK5)
  • ReentrantLock construction method:
Method nameexplain
ReentrantLock()Create an instance object of ReentrantLock
  • How to obtain and release locks in Lock:
Method nameexplain
void lock()Acquire lock
void unlock()Release lock
  • It is recommended to use try{} finall {} code block to lock and release locks
package test;

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

public class SellTicket implements Runnable{
    private static int tickets = 100;
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true) {
            try {
                lock.lock();
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "The second is being sold" + tickets + "Ticket");
                    tickets--;
                }
            }finally {
                lock.unlock();
            }
        }
    }
}

1.13 thread communication

  • Thread communication must be required only when multiple threads operate the same resource
Method nameexplain
public void wait()To put the current thread into a waiting state, this method must be called on the lock object
public void notify()Wake up a thread in the waiting state on the current lock object. This method must be called on the lock object
public void notifyAll()Wake up all threads waiting on the current lock object. This method must be called on the lock object

1.14 producers and consumers

1.14.1 overview of producers and consumers

  • In order to reflect the waiting and awakening in the process of production and consumption, Java provides several methods for us to use. These methods are in the Object class
  • Wait and wake methods of Object class
Method nameexplain
void wait()Causes the current thread to wait until another thread calls the notify() method or notifyAll() method of the object
void notify()Wake up a single thread waiting for the object monitor
void notifyAll()Wake up all threads waiting for the object monitor

1.14.2 producer consumer cases

  • Milk boxes
package test;

//1: Define milk box class
public class Box {
    //Define a member variable to represent the x bottle of milk
    private int milk;
    //Define a member variable to represent the state 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 waiting to be consumed
        if(state) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //If there is no milk, produce milk
        this.milk = milk;
        System.out.println("The milkman will" + this.milk + "Put a bottle of milk into the milk box");

        //Modify the milk box status after production
        state = true;

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

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

        //Modify the milk box status after consumption
        state = false;

        //Wake up other waiting threads
        notifyAll();
    }
}
  • Producer class
package test;

//2: Producer class: implements the Runnable interface
public class Producer implements Runnable {
    private Box b;

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

    //Override the run() method to call the operation of storing milk
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            b.put(i);
        }
    }
}
  • Consumer category
package test;

//3: Customer; Implement Runnable interface
public class Customer implements Runnable{
    private Box b;

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

    //Override the run() method to call the operation to get milk
    @Override
    public void run() {
        while(true) {
            b.get();
        }
    }
}
  • Test class
package test;

public class BoxDemo {
    public static void main(String[] args) {
        //Create a milk box object, which is a shared data area
        Box b = new Box();

        //Create a producer object and pass the milk box object as a construction method parameter. Because the operation of storing milk is called in this class
        Producer p = new Producer(b);

        //Create a consumer object and pass the milk box object as a constructor parameter, because the operation to get milk is called in this class
        Customer c  =new Customer(b);

        //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();

//        The milkman put the first bottle of milk into the milk box
//                The user gets the first bottle of milk
//        The milkman put the second bottle of milk into the milk box
//                The user gets the second bottle of milk
//        The milkman put the third bottle of milk into the milk box
//                The user gets the third bottle of milk
//        The milkman put the fourth bottle of milk into the milk box
//                The user gets the fourth bottle of milk
//        The milkman put the fifth bottle of milk into the milk box
//                The user gets the fifth bottle of milk
    }
}

Keywords: Java JavaSE

Added by johnmess on Thu, 13 Jan 2022 21:55:15 +0200