Java advanced programming - multithreading (lifecycle + thread synchronization)

1. Thread life cycle

1.1. Five states of threads

  • Thread. Is used in JDK The state class defines several states of a thread

New: when a thread class or its subclass object is declared and created, the new thread object is in the new state

Ready: after the newly created thread is started (), it will enter the thread queue and wait for the CPU time slice. At this time, it has met the running conditions, but it has not been allocated to the CPU.

Run: the process in the ready state is scheduled and obtains the CPU, and enters the running state. The run() method defines the operation and function of the thread

Blocking: under special circumstances, when the input / output operation is suspended or executed artificially, give up the CPU and temporarily suspend its execution to enter the blocking state

Death: the thread has completed all its work and is forced to terminate in advance or terminated due to an exception

1.2 switching relationship of five states

2. Thread synchronization (key)

To solve the thread safety problem

2.1 problem raising - multi window ticket selling

Duplicate ticket

Wrong ticket

analysis:

 * 1,In the process of buying tickets, there are duplicate tickets and wrong tickets--->A thread safety problem has occurred
 * 2,Cause of the problem: when one thread operates the ticket, other threads also participate in the ticket operation when the operation has not been completed
 * 3,Solution: when a thread is operating ticket Other threads cannot participate until the operation of the current thread ends.Finally, even if the current thread is blocked, it cannot be changed
  • The uncertainty of multi thread execution leads to the uncertainty of execution results
  • Operation of multiple thread heap sharing data

2.2 solving thread safety problems through thread synchronization mechanism in Java

2.2. 1. Method 1: synchronized code block

2.2. 1.1 synchronous code block solves the thread safety problem of implementing Runnable interface class

synchronized(Synchronization monitor){
		//Code to be synchronized
}
Note: 1. The code that operates the shared data is the code that needs to be synchronized
		2,Synchronization monitor(lock),The object of any class can act as a lock
					Requirement: multiple threads must be shared**Same lock**

Modify the implementation class code:

class Window1 implements  Runnable{

    private  int ticket = 100;
    //1. Create a new object of any class
    Object obj = new Object();


    @Override
    public void run() {
        while (true) {
        //2. Lock code that operates on shared data
            synchronized (obj) {
                if (ticket > 0) {

                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + "A ticket is sold at the window,Current remaining tickets" + (ticket));
                } else break;

            }
        }
    }
}

Add: the synchronization monitor here can be an object of any class and unique. Note that the parameter here can also be the current object itself, that is, the parameter here can be (this)

            synchronized(this){//synchronized (obj) {
                if (ticket > 0) {
                    ticket--;
                    System.out.println(getName() + "A ticket is sold at the window,Current remaining tickets" + (ticket));
                } else break;
            }

2.2. 1.2 synchronous code block solves the Thread safety problem of implementing Thread class

Subclass Code:

class Window extends  Thread{

    private static int ticket = 100;
    //1. In order to ensure the same seat when "locked", the chair class needs static decoration
    private static Object obj  = new Object();
    Window(){}

    Window(String name){
        super(name);
    }
    @Override
    public void run() {
        while (true) {
            //2. Lock
            synchronized (obj) {
                if (ticket > 0) {
                    ticket--;
                    System.out.println(getName() + "A ticket is sold at the window,Current remaining tickets" + (ticket));

                } else break;
            }
        }
    }
}

Add: the synchronization monitor here can be (current class name. Class)

            synchronized (Window.class) {//The class is also an object, and the class is loaded only once
                if (ticket > 0) {
                    ticket--;
                    System.out.println(getName() + "A ticket is sold at the window,Current remaining tickets" + (ticket));
                } else break;
            }

2.2. 2. Mode 2: synchronization method

If the code that operates on shared data is completely declared in a method, we can synchronize this method

2.2. 2.1 the synchronization method solves the thread safety problem of implementing Runnable interface class

Implementation class:

class Thread2 implements  Runnable{

    private  int ticket = 100;


    @Override
    public void run() {
        while (true) {
            show();
        }
    }


    private  synchronized void show(){//Synchronization monitor this at this time
        if (ticket > 0) {

            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticket--;
            System.out.println(Thread.currentThread().getName() + "A ticket is sold at the window,Current remaining tickets" + (ticket));

        }
    }

}

2.2. 2.2 the synchronization method solves the Thread safety problem of implementing Thread class

class Window1 extends  Thread{

    private static int ticket = 100;

    Window1(){}

    Window1(String name){
        super(name);
    }
    @Override
    public void run() {
        while (true) {
            show();
        }
    }

    private static synchronized   void show(){//Sync monitor Window1 class
        if (ticket > 0) {

            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticket--;
            System.out.println(Thread.currentThread().getName() + "A ticket is sold at the window,Current remaining tickets" + (ticket));
        }
    }

}

2.2. 3 summary of synchronization methods

* The synchronization method still involves the synchronization monitor, but does not need to be declared explicitly
* wrong static The synchronization monitor is this
* static The monitor is the current class itself( Xxxx.class)

2.2. 4 advantages and disadvantages of synchronization

Advantages: solves the thread safety problem
Insufficient: when operating synchronization code, other threads wait indiscriminately. Equivalent to a single thread, low efficiency

2.2. Two problems of synchronization method——

2.2. 5.1 rewrite singleton mode (lazy) to thread safe

class  Bank{
    private Bank(){}


    private static  Bank instance = null;


    public static  Bank getInstance(){
//Mode 1: poor efficiency
/*        synchronized (Bank.class){
            if (instance == null) {
                instance  = new Bank();
            }
            return instance;
        }*/


//Mode 2:
        if(instance == null ){
            synchronized (Bank.class){
                if (instance == null) {
                    instance  = new Bank();
                }

            }
        }
        return instance;


    }

}

2.2. 5.2 deadlock problem

Causes of deadlock

* Different threads occupy the synchronization resources needed by the other party and do not give up. They are waiting for the other party to give up the resources they need, forming a thread deadlock
* There will be no exception or prompt after deadlock, but all threads are blocked and cannot continue

Deadlock code example

public class ThreadTest {

    public static void main(String[] args) {

        StringBuffer s1 = new StringBuffer();
        StringBuffer s2 = new StringBuffer();


        new Thread(){
            @Override
            public void run() {
                synchronized(s1){
                    s1.append("a");
                    s2.append("1");


                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (s2){
                        s1.append("b");
                        s2.append("2");


                        System.out.println(s1);;
                        System.out.println(s2);
                    }
                }
            }
        }.start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized(s2){
                    s1.append("C");
                    s2.append("3");

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    synchronized (s1){
                        s1.append("D");
                        s2.append("4");


                        System.out.println(s1);;
                        System.out.println(s2);
                    }
                }
            }
        }).start();

    }

}

Solution to deadlock

* Specialized algorithms
* Minimize the definition of synchronization resources
* Try to avoid nested synchronization

2.3 solving thread safety problems - mode 3 lock lock

public class LockTest {

    public static void main(String[] args) {
        Window w1 = new Window();
        Thread t1 = new Thread(w1);
        Thread t2 = new Thread(w1);
        Thread t3 = new Thread(w1);

        t1.setName("Window one");
        t2.setName("Window II");
        t3.setName("Window three");

        t3.start();
        t2.start();
        t1.start();
    }




}

class  Window implements Runnable{

    private int ticket = 100;

    //Instantiate ReentrantLock
    private  ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {

        while (true){
            try {

                //Call lock() method
                lock.lock();

                if (ticket > 0) {
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":Ticket No.:"+ticket);
                    ticket--;
                }else break;
            }finally {
                //3. Call unlock() to unlock the method
                lock.unlock();
            }

        }

    }
}

2.4 similarities and differences between synchronized and lock

2.4. 1 same

Can solve thread safety problems

2.4. 2 different

synchronized: automatically release the synchronization monitor after executing the corresponding synchronization code
Lock needs to manually start synchronization lock(), and it also needs to be manually implemented (unlock()) at the end

Priority order

Lock > > sync code block > > sync method

Keywords: Java Multithreading

Added by Hybrid Kill3r on Sat, 18 Dec 2021 18:29:01 +0200