[JAVA] notes (20) -- deadlock; How to solve thread safety problems; Daemon thread; Timer; Callable implementation thread; wait() and notify(); Realize the producer and consumer model;

Deadlock:

1. Features: since deadlock will not cause exceptions or errors, the program will always be stuck here, so this error is difficult to debug;

2. Deadlock model:

public class ThreadPra1 {
    public static void main(String[] args) {
        //Create object1, object2 objects
        Object object1=new Object();
        Object object2=new Object();
        //Let thread1 thread and thread2 thread share object1 and object2 objects
        Thread thread1=new MyThread1(object1,object2);
        Thread thread2=new MyThread2(object1,object2);
        //Start thread1 thread and thread2 thread in turn, and "deadlock" occurs
        thread1.start();
        thread2.start();
    }
}
class MyThread1 extends Thread{
    Object object1;
    Object object2;
    public MyThread1(Object object1, Object object2) {
        this.object1 = object1;
        this.object2 = object2;
    }
    public void run() {
        //This thread takes the object lock of object1 first, and then the object lock of object2
        synchronized (object1){
            //After thread1 thread gets the object1 lock, sleep for 1 second to ensure that thread2 thread can get the object2 lock
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (object2){

            }
        }
    }
}
class MyThread2 extends Thread{
    Object object1;
    Object object2;
    public MyThread2(Object object1, Object object2) {
        this.object1 = object1;
        this.object2 = object2;
    }
    public void run() {
        //This thread takes the object lock of object2 first, and then the object lock of object1
        synchronized (object2){
            synchronized (object1){

            }
        }
    }
}

 

How to solve thread safety problems:

The first scheme: try to use local variables instead of "instance variables and static variables";

The second scheme: if it must be an instance variable, you can consider creating multiple objects so that the memory of the instance variable is not shared (one thread corresponds to one object, 100 threads correspond to 100 objects, and if the objects are not shared, there is no data security problem)

The third scheme: if you can't use local variables and create multiple objects, you can only choose "synchronized thread synchronization mechanism" at this time;

synchronized will reduce the execution efficiency of the program, the user experience is poor, the user throughput of the system is reduced, and the user experience is poor. If you have to choose the thread synchronization mechanism;

 

Daemon thread:

1. Features: dead loop, the daemon thread executes until all user threads end, and the daemon thread ends automatically (such as garbage collection thread);

2. Implement daemon thread: call method---     Thread. Setdaemon (true);  

public class ThreadPra1 {
    public static void main(String[] args) {
        BakDataThread bakDataThread=new BakDataThread();
        bakDataThread.setName("Backup data thread");
        //Set the bakDataThread thread as the daemon thread
        bakDataThread.setDaemon(true);
        bakDataThread.start();
        for (int i=0;i<10;i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Downloading files...");
        }
    }
}
class BakDataThread extends Thread{
    public void run() {
        int i=1;
        //Dead cycle
        while (true){
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"implement"+(i++)+"second");
        }
    }
}
Run instance
Downloading files...
Downloading files...
Downloading files...
Downloading files...
The backup data thread executes once
 Downloading files...
Downloading files...
Downloading files...
Downloading files...
Downloading files...
The backup data thread executes twice
 Downloading files...

Process finished with exit code 0

 

Timer:

1. Function: execute specific procedures at specific intervals; for example, perform general ledger operation of bank account every week; backup data every day;

2. Implementation method:

1) Use the sleep method to set the sleep time, wake up and automatically continue to perform tasks. This method is the most original timer (rarely used now);

2) Java. Util. Timer / / a special timer class

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class ThreadPra1 {
    public static void main(String[] args) throws ParseException {
        //Create Timer object
        Timer timer=new Timer();
        //Specify time format
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        //Get this time
        Date date=sdf.parse(sdf.format(new Date()));
        //Execute the timer task. The start time is now and the interval is 5 seconds
        timer.schedule(new LogTimerTask(),date,5000);
        //Execute the timer task. The start time is now and the interval is 1 second
        timer.schedule(new TimerTask() {
            public void run() {
                System.out.println("Importing data...");
            }
        }, date, 1000);
    }
}
//The custom timer task class inherits TimerTask and overrides the run method
class LogTimerTask extends TimerTask{
    public void run() {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        System.out.println(sdf.format(new Date())+":Successfully backed up data");
    }
}
Run instance
2021-12-04 00-35-54:Successfully backed up data
 Importing data...
Importing data...
Importing data...
Importing data...
Importing data...
2021-12-04 00-35-59:Successfully backed up data
 Importing data...
Importing data...
Importing data...
Importing data...
Importing data...
2021-12-04 00-36-04:Successfully backed up data
 Importing data...
Importing data...
Importing data...
Importing data...
Importing data...
2021-12-04 00-36-09:Successfully backed up data
......

#Summarize the use of Timer:

First, customize the timer task class (inheriting TimerTask) and override the run method;

Second, create a Timer object;

Third, call   Timer. schedule (timer task object, Date object, how many milliseconds is the interval between execution)   // The corresponding time of the date object is the first execution time of the timer task

3) In the actual development, the SpringTask framework provided in the Spring framework is widely used. As long as this framework is simply configured, it can complete the task of the timer;

 

The third way to implement threads:

1. Implement the Callable interface (a new feature of JDK8). The thread implemented in this way can obtain the return value of the thread; the two methods described earlier cannot obtain the return value of the thread, because the run method returns void;

2. Use of callable:  

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class ThreadPra1 {
    public static void main(String[] args) throws Exception{
        //Create FutureTask object and implement Callable interface with anonymous inner class
        FutureTask task=new FutureTask(new Callable() {
            //The call method is equivalent to the run method, but the call method has a return value
            public Object call() throws Exception {
                int a=100;
                int b=100;
                //After the simulated branch thread executes for three seconds, the run method ends
                Thread.sleep(3000);
                //Automatic packing mechanism
                return a+b;
            }
        });
        Thread thread=new Thread(task);
        thread.start();
        System.out.println("Branch thread execution result:"+task.get());
        System.out.println("The branch thread is really inky. The main thread indicates that I can finally be liberated from the blocking state!");
    }
}
Run instance
Branch thread execution result: 200
 The branch thread is really inky. The main thread indicates that I can finally be liberated from the blocking state!

Process finished with exit code 0

#Summarize the use of Callable:

First, create a FutureTask object and pass an anonymous inner class to the constructor (implement the Callable interface and override the call method)

Second, create a Thread object and pass the FutureTask object created above to the constructor;

Third, start the Thread object Thread;

3. Advantages and disadvantages of this thread implementation method:

Advantages: it can obtain the execution result of the thread;

Disadvantages: low efficiency. When obtaining the thread execution results, the current thread is blocked, resulting in reduced efficiency;

 

wait() and notify() in Object class:

1. Call of wait method and notify method:

Object object. Wait(); / / enable the current thread active on the object object to wait indefinitely until it is awakened;

Object object. notify(); / / wake up a thread waiting on the object object;

Object object. notifyAll() / / wake up all threads waiting on the object object;

2. Implement "producer and consumer mode" through wait() and notify():

import java.util.ArrayList;
import java.util.List;
public class ThreadPra1 {
    public static void main(String[] args) throws Exception{
        List list=new ArrayList();
        Thread thread1=new Thread(new Producer(list));
        Thread thread2=new Thread(new Consumer(list));
        thread1.setName("Producer thread");
        thread2.setName("Consumer thread");
        thread1.start();
        thread2.start();
    }
}
class Producer implements Runnable{
    private List list;
    public Producer(List list) {
        this.list = list;
    }
    public void run() {
        //Lock the list object so that the list object becomes a common resource for producers and consumers
        synchronized (list){
            //Dead cycle
            while (true){
                //When the warehouse is full, put the producer thread into waiting
                if (list.size()>0){
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //Storage warehouse
                list.add(new Object());
                System.out.println(Thread.currentThread().getName()+"--->"+list.get(0));
                //Wake up the consumer thread for consumption
                list.notify();
            }
        }
    }
}
class Consumer implements Runnable{
    private List list;
    public Consumer(List list) {
        this.list = list;
    }
    public void run() {
        //The list object is a shared resource
        synchronized (list){
            //Dead cycle
            while (true){
                //When the warehouse is empty, the consumer thread is caught waiting
                if (list.size()==0){
                    try {
                        list.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName()+"--->"+list.get(0));
                //Empty warehouse
                list.remove(0);
                //Wake up the producer thread for production
                list.notify();
                //list.notifyAll(); it's OK to wake up both producers and consumers, because even if consumers are awakened, they will be intercepted by if conditional sentences and fall into waiting again
            }
        }
    }
}
Run instance
Producer thread--->java.lang.Object@7941b718
 Consumer thread--->java.lang.Object@7941b718
 Producer thread--->java.lang.Object@77865640
 Consumer thread--->java.lang.Object@77865640
 Producer thread--->java.lang.Object@73b9dc68
 Consumer thread--->java.lang.Object@73b9dc68
 Producer thread--->java.lang.Object@36bb5c7b
 Consumer thread--->java.lang.Object@36bb5c7b
 Producer thread--->java.lang.Object@42b6d4c3
 Consumer thread--->java.lang.Object@42b6d4c3
......

a key:

The Object. Wait method will make the current thread active on the Object object enter the waiting state and release the lock of the Object object previously occupied;

The object. Notify method only notifies, does not release the lock of the o object previously occupied, and continues to execute the thread until the run method ends;

The wait method and notify method are based on thread synchronization, because multiple threads have to operate a warehouse at the same time, so there is a thread safety problem;

ps: since the blogger is only a baby ape, some places may be partial. It would be better if the predecessors could give some advice       (~ ̄(OO) ̄)ブ

 

 

Keywords: java-se

Added by Grisu on Sat, 04 Dec 2021 06:37:32 +0200