Java thread Foundation

Posted by Megahertza on Sat, 05 Mar 2022 00:59:15 +0100

[Han Shunping talks about Java] one day learn Thread Synchronized mutex lock, process parallel concurrent deadlock, etc note

thread

Thread introduction

process
  1. Process refers to the running program, and the operating system allocates memory space for the process
  2. A process is an execution process of a program, or a running program. It is a dynamic process: it has its own process of emergence, existence and extinction.
thread
  1. A thread is created by a process and is an entity of the process

  2. A process can have multiple threads

  3. Single thread: only one thread is allowed to execute at the same time

  4. Multithreading hum: multiple threads can be executed at the same time

  5. Concurrency * *: multiple tasks are executed alternately * * at the same time, resulting in the illusion of "seemingly simultaneous". In short, multitasking realized by single core CPU is concurrency. (eg: people have only one brain, and they are multitasking.)

  6. Parallel: * * multiple tasks are executed simultaneously** Multi core CPU can realize parallel.

  7. Concurrency and parallelism can exist on the same computer

    java to obtain computer process information

    public class RuntimeTest {
        public static void main(String[] args) {
            //Gets the runtime object associated with the java program
            var rt=Runtime.getRuntime();
            //Get the number of CPUs -- > cores of the current computer: the number of processes that can be executed simultaneously. availableProcessors
            System.out.println("Number of processors:"+rt.availableProcessors());
            System.out.println("Free memory:"+rt.freeMemory());
            System.out.println("Total memory:"+rt.totalMemory());
            System.out.println("Maximum memory available:"+rt.maxMemory());
        }
    }
    

Basic thread usage

  1. Inherit Thead class and override run method
  2. Implement the Runnable interface and rewrite the run method
Thread use case - inherit Thead class and override run method
/*
 * Demonstrates creating a thread by inheriting the Thead class
 * */

import jdk.swing.interop.SwingInterOpUtils;

public class Thead01 {
    public static void main(String[] args) {
        //Create a cat object that can be used as a thread
        //crtl+j displays the shortcut keys of all shortcut keys

        Cat cat = new Cat();
        //start() source code
        /*
        (1)
        public synchronized void start() {
              start0();
        }
       (2)
        //start0 It is a local method, a JVM call, and the bottom layer is a c/c + + implementation
        //The real function of multithreading is start0(), not the run method. In fact, the run method is called by the multithreading mechanism in start0()
         private native void start0();
        */

        cat.start(); //When the thread is started, the run method will be called automatically
        //cat. run(); // The run method is an ordinary method. If a thread is not really started, the run method will be executed until it is completed. Equivalent to serialization, not multithreading
        //Note: when the main thread starts a sub thread thread Thread-0, the main thread will not block and will continue to execute

        System.out.println("Main thread" + Thread.currentThread().getName() + "Continue execution");
        for (int i = 0; i < 10; i++) {
            System.out.println("Main thread i=" + i);
            //Hibernate the main thread
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

//1. When a class inherits Thead class, it can be used as a thread
class Cat extends Thread {
    @Override
    public void run() { //Rewrite the run method to realize its own business logic
        int time = 0;
        while (true) {
            //The thread outputs "meow, meow, I'm a kitten" on the console every 1 second
            System.out.println("Meow, meow, I'm a kitten" + (++time) + " Thread Name:" + Thread.currentThread().getName());
            //Let the thread sleep for 1 second crtl+alt+t

            try {
                Thread.sleep(1000); //The unit is milliseconds
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (time == 8) {
                break;
            }
        }
    }
}
Thread use case - implement the Runnable interface and rewrite the run method
//Implement the Runnable interface and rewrite the run method
public class Thread02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        // dog.start();  Start cannot be called here
        //Create a Thread object, put the dog object (Runnable) into the Thread
        Thread thread = new Thread(dog);
        thread.start();

        Tiger tiger = new Tiger();
        ThreadProxy threadProxy = new ThreadProxy(tiger);
        threadProxy.start();
    }
}

class Animal{}
class Tiger extends Animal implements Runnable{
    @Override
    public void run() {
        System.out.println("The tiger howled.....");
    }
}

//Thread proxy class, which simulates the simplest thread class
class ThreadProxy implements Runnable{ //You can think of the ThreadProxy class as a Thread
    private Runnable target=null;

    @Override
    public void run() {
          if(target != null){ //Dynamic binding (runtime type tiger)
              target.run();
          }
    }

    public ThreadProxy(Runnable target) {
        this.target = target;
    }

    public void start(){
        start0(); //This method is a real way to implement multithreading
    }

    private void start0(){
        run();
    }

}

class Dog implements Runnable{ //Develop threads by implementing Runnable interface
    int count=0;
    @Override
    public void run(){ //Common method
        while (true){
            System.out.println("The dog barks...Hi"+(++count)+" "+Thread.currentThread().getName());

            //Sleep for 1 second
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (count==10){
                break;
            }
        }
    }
}
Thread use case - multithreaded execution
/*
 * main Thread starts two child threads
 * */

public class Thread03 {
    public static void main(String[] args) {
        T1 t1 = new T1();
        T2 t2 = new T2();
        Thread thread1 = new Thread(t1);
        Thread thread2 = new Thread(t2);
        thread1.start();
        thread2.start();
    }
}

class T1 implements Runnable {
    int count = 0;

    @Override
    public void run() {
        while (true) {
            //Output "hello world" every 1 second and output 10 times
            System.out.println("hello world" + (++count) + "~~~");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (count == 10) {
                break;
            }
        }
    }
}

class T2 implements Runnable {
    int count = 0;

    @Override
    public void run() {
        while (true) {
            //Output "hi" every 1 second for 5 times
            System.out.println("hi" + (++count) + "~~~");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (count == 5) {
                break;
            }
        }
    }
}
The difference between inheriting thread and implementing Runnable

The implementation of Runnable interface is more suitable for multiple threads sharing a resource, and avoids the limitation of single inheritance. It is recommended to use the Runnable interface.

T3 t3=new T3("hello");
Thread thread1 = new Thread(t3);
Thread thread2 = new Thread(t3);
thread1.start();
thread2.start();

System.out.println("Main thread completed");
Ticket issue

Ticketing system - simulate and program three ticketing windows 100, which are implemented by inheriting Thread and Runnable respectively, and analyze the problem?

Problem – > oversold will occur

package ticket;

public class SellTicket {
    public static void main(String[] args) {
        /*
        //test
        SellTicket01 sellTicket01 = new SellTicket01();
        SellTicket01 sellTicket02 = new SellTicket01();
        SellTicket01 sellTicket03 = new SellTicket01();

        //There will be oversold
        sellTicket01.start();
        sellTicket02.start();
        sellTicket03.start();
        */

        SellTicket02 sellTicket02 = new SellTicket02();
        Thread thread1 = new Thread(sellTicket02);
        Thread thread2 = new Thread(sellTicket02);
        Thread thread3 = new Thread(sellTicket02);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

//Using Thread
class SellTicket01 extends Thread {
    public static int ticketNum = 100; //Let multiple threads share ticketNum

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

            if (ticketNum < 0) {
                System.out.println("End of ticket sales.....");
                break;
            }

            //Sleep for 50 seconds
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("window" + Thread.currentThread().getName() + "Sell a ticket" + ",Remaining votes=" + (--ticketNum));
        }
    }
}

//Using Runnable
class SellTicket02 implements Runnable {
    public static int ticketNum = 100; //Let multiple threads share num

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

            if (ticketNum < 0) {
                System.out.println("End of ticket sales.....");
                break;
            }

            //Sleep for 50 seconds
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("window" + Thread.currentThread().getName() + "Sell a ticket" + ",Remaining votes=" + (--ticketNum));
        }
    }
}

Common thread methods

Common basic methods

  1. setName / / set the thread name to be the same as the parameter name
  2. getName / / returns the name of the thread
  3. Start / / start the thread to execute; The bottom layer of java virtual machine calls the start0 method of the thread
  4. Run / / call the thread object run method
  5. setPriority / / change thread priority
  6. getPriority / / set thread priority
  7. Sleep / / sleep (pause) the currently executing thread within the specified number of milliseconds
  8. interrupt / / terminal thread
Precautions and details
  1. The bottom layer of start will create a new thread and call run. Run is a simple method call and will not start a new thread
  2. Thread priority range MIN_PRIORITY=1, NORM_PRIORITY=5 , MAX_PRIORITY=10;
  3. Interrupt, interrupt the thread, but there is no real end thread. Therefore, it is generally used for Interrupt a dormant thread
  4. Sleep: the static method of the thread, which makes the current thread sleep
package method;

public class ThreadMethod01 {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.setName("laohan");
        t.setPriority(Thread.MIN_PRIORITY);
        t.start(); //Start child thread

        // The main thread prints five hi's and then interrupts the sleep of the child thread
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + " hi" + i);
        }
        System.out.println(t.getName() + " thread priority =" + t.getPriority());
        t.interrupt(); //When the execution reaches this point, the sleep of the child thread will be interrupted

    }
}

class T extends Thread {
    @Override
    public void run() {
        while (true) {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + " Eat steamed stuffed bun~~~" + i);
            }
            try {
                System.out.println(Thread.currentThread().getName() + " Dormant~~~");
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + " cover interrupt Yes~~~");
            }
        }
    }
}

yield and join

  1. yield: the comity of threads. Give up the cpu and let other threads execute, but the comity time is uncertain, so it is not necessarily successful [comity is to make Thread.yield()]
  2. join: queue jumping of threads. Once queue jumping is successful, all tasks of inserting thread must be completed [queue jumping is someone else inserting t2.join();]
package method;

public class ThreadMethod02 {
    public static void main(String[] args) throws InterruptedException {
        T2 t2 = new T2();
        t2.start();

        for (int i = 1; i <= 20; i++) {
            Thread.sleep(1000);
            System.out.println("Main thread (younger brother)" + " Yes" + i + "steamed stuffed bun");
            if (i == 5) {
                System.out.println("The main thread (boy) let the child thread (boss) eat first");
                //join() jump the queue and you will succeed
                //t2.join(); // Let the child thread jump the queue and finish execution

                Thread.yield(); //Comity is not necessarily successful

                System.out.println("The child thread (boss) eats up the main thread (younger brother)");
            }
        }
    }
}

class T2 extends Thread {
    @Override
    public void run() {

        for (int i = 1; i <= 20; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread (boss) eat" + i + "steamed stuffed bun");
        }
    }
}

User thread and daemon thread

  1. User thread: also known as worker thread, when the task of the thread is completed or the notification method ends

  2. Daemon thread: it generally serves the working thread, When all user threads end, the daemon thread ends automatically [Thread.setDaemon(true): set as daemon thread]

  3. Common daemon thread: garbage collection mechanism

    package method;
    
    public class ThreadMethod03 {
        public static void main(String[] args) throws InterruptedException {
            MyDaemonThread myDaemonThread = new MyDaemonThread();
            //If you want the main thread to end, the child thread will end automatically
            //Just set the child thread as the daemon thread
            myDaemonThread.setDaemon(true);
            myDaemonThread.start();
            for (int i = 0; i < 10; i++) {
                System.out.println("Hard work....");
                Thread.sleep(1000);
            }
    
        }
    
    }
    class MyDaemonThread extends Thread {
        public void run() {
            for (; ; ) {//Infinite loop
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Happy chat, ha ha ha~~~");
            }
        }
    }
    
    

Thread life cycle

Thread. Is used in JDK The state enumeration represents several states of a thread

First, the status of threads can be divided into 6 or 7 states. The specific states are as follows

6 states

  • New: new status
  • Runnable: runnable state
  • Terminated: terminated status
  • Waiting: waiting state
  • TimedWaiting: timeout waiting state
  • Blocked: blocking status

7 State

  • New: new status
  • Ready: ready status
  • Running: running status
  • Terminated: terminated status
  • Waiting: waiting state
  • TimedWaiting: timeout waiting state
  • Blocked: blocking status

In fact, there is little difference between state 6 and state 7, but state 7 disassembles the Runnable state into Ready state and Running state.

Thread state transition diagram

Sychronized

Thread synchronization mechanism

  1. In multithreaded programming, some sensitive data is not allowed to be accessed by multiple threads at the same time. At this time, synchronous access technology is used, Ensure that at most one thread can access the data at any one time to ensure the integrity of the data.
  2. It can also be understood as follows: thread synchronization, that is, when a thread is operating on memory, other threads can not operate on the memory address until the thread is completed.

Synchronization specific method - synchronized

1. Synchronous code block
    
    Sychronized (Object){ //Get the lock of the object before you can operate the synchronization code
          //Code to be synchronized;
}

2. Sychronized It can also be placed in the method declaration to represent the whole method-Synchronization method
    
    public synchronized void m(String name){
      //Code to be synchronized;
}
[ticket issue] - synchronization mechanism: there will be no oversold
package ticket;

public class SellTicket {
    public static void main(String[] args) {
   
        //test
        SellTicket03 sellTicket03 = new SellTicket03();
        Thread thread1 = new Thread(sellTicket03);
        Thread thread2 = new Thread(sellTicket03);
        Thread thread3 = new Thread(sellTicket03);
        thread1.start();
        thread2.start();
        thread3.start();

    }
}

//Use Runnable and synchronized to synchronize threads
class SellTicket03 implements Runnable {
    public static int ticketNum = 100; //Let multiple threads share ticketNum
    private boolean loop=true;
    
    public synchronized void sell(){//Synchronous method. At the same time, only one thread can execute the sell method
        if (ticketNum <= 0) {
            System.out.println("End of ticket sales.....");
            loop=false;
            return;
        }
        //Sleep for 50 seconds
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("window" + Thread.currentThread().getName() + "Sell a ticket" + ",Remaining votes=" + (--ticketNum));
    }

    @Override
    public void run() {
        while (loop) {
              sell();  //sell is a synchronization method
        }
    }
}

mutex

  1. java language, introduced Object mutex To ensure the integrity of shared data operations
  2. Each object corresponds to a tag that can be called a mutex , this flag is used to ensure that only one thread can access the object at any time
  3. Keyword synchronized to associate with the mutex of the object. When an object is decorated with synchronized, it indicates that the object can only be accessed by one thread at any time
  4. Limitation of synchronization: it leads to the reduction of program execution efficiency
  5. The lock of the synchronization method (non static) can be this or other objects (the same object is required)
  6. The lock of the synchronous method (static) is the current class itself
public class SellTicket {
    public static void main(String[] args) {

        //test
        SellTicket03 sellTicket03 = new SellTicket03();
        Thread thread1 = new Thread(sellTicket03);
        Thread thread2 = new Thread(sellTicket03);
        Thread thread3 = new Thread(sellTicket03);
        thread1.start();
        thread2.start();
        thread3.start();

    }
}

//Use Runnable and synchronized to synchronize threads
class SellTicket03 implements Runnable {
    public static int ticketNum = 100; //Let multiple threads share ticketNum
    private boolean loop=true;
    Object object =new Object();

    //The lock of the synchronous method (static) is the current class itself
    //1. Public synchronized static void m1() {} lock on sellticket03 class
    //2. If you want to implement a synchronous code block in a static method, the mutex is sellticket03 class
    public synchronized static void m1(){

    }
    public static void m2(){
        synchronized (SellTicket03.class){
            System.out.println("m2");
        }
    }


    //1. public synchronized void sell() {} is a synchronization method
    //2. Lock this object at this time
    //3. You can also write synchronized on the code block, synchronize the code block, and mutually exclusive lock on this object
    public /*synchronized*/ void sell(){//Synchronous method. At the same time, only one thread can execute the sell method

        synchronized(/*this*/ object){      //Changed to nchronized(new Object()) and oversold again. The lock fails because it is not the same lock object
        if (ticketNum <= 0) {
            System.out.println("End of ticket sales.....");
            loop=false;
            return;
        }
        //Sleep for 50 seconds
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("window" + Thread.currentThread().getName() + "Sell a ticket" + ",Remaining votes=" + (--ticketNum));
        }
    }

    @Override
    public void run() {
        while (loop) {
              sell();  //sell is a synchronization method
        }
    }
}

Precautions and details

  1. If the synchronization method is not decorated with static, the default object is this

  2. If the synchronization method is decorated with static, the default lock object is: Current class class

  3. Implementation steps:

    • You need to analyze the locked code first
    • Select a synchronization code block or synchronization method
    • requirement Lock object for multiple threads For the same one! [multiple threads compete for the same lock object]

deadlock

/*
 * Simulate thread deadlock
 * */
public class DeadLock {
    public static void main(String[] args) {
        //Simulated deadlock phenomenon
        DeadLockDemo A = new DeadLockDemo(true);
        A.setName("A");
        DeadLockDemo B = new DeadLockDemo(false);
        B.setName("B");
        A.start();
        B.start();

    }
}

//thread 
class DeadLockDemo extends Thread {
    static Object o1 = new Object();  //Ensure multithreading and share an object. Here, use static
    static Object o2 = new Object();
    boolean flag;

    public DeadLockDemo(boolean flag) {
        this.flag = flag;
    }

    public void run() {
        //The following is the analysis of business logic
        //1. If the flag is T, thread A will get the o1 object lock first, and then try to get the o2 object lock
        //2. If thread A cannot get o2 object lock, it will be Blocked
        //3. If the flag is F, thread B will get the o2 object lock first, and then try to get the o1 object lock
        //4. If thread B cannot get the o1 object lock, it will be Blocked
        if (flag) {
            synchronized (o1) { //Object mutex, the following is the synchronization code
                System.out.println(Thread.currentThread().getName() + "Enter 1");
                synchronized (o2) { //Here you can get the full name of the li object
                    System.out.println(Thread.currentThread().getName() + "Enter 2");
                }
            }
        } else {
            synchronized (o2) {
                System.out.println(Thread.currentThread().getName() + "Enter 3");
                synchronized (o1) { //Here you can get the full name of the li object
                    System.out.println(Thread.currentThread().getName() + "Enter 4");
                }
            }
        }
    }
}

Release lock

The following operation will release the lock
  1. Synchronization method and synchronization code block of the current thread end of execution
  2. The current thread encountered an error in the synchronization method and synchronization code block break,return
  3. The current thread has unprocessed in the synchronization method and synchronization code block Error or Exception , resulting in an abnormal end
  4. The current thread executes the of thread object in synchronization method and synchronization code block wait() method , the current thread pauses and releases the lock
The following operation will not release the lock
  1. When a thread executes a synchronous method or a synchronous code block, the program calls Thread.sleep(),Thread.yield() method Pauses the execution of the current thread without releasing the lock

  2. When a thread executes a synchronized code block, other threads call the thread's suspend() method The thread Hang

    • Tip: try to avoid using suspend() and resumen() to control threads. This method is not recommended

Topics: Java