Advanced Basics - threads

Thread example:
String family:
StringBuilder threads are asynchronous, unsafe, but efficient.
StringBuffer thread synchronization, high security

***
1. Process and thread: each task running in the operating system corresponds to a process. When a program runs in memory, it becomes a process. Process is an independent unit of the operating system for group member allocation and scheduling.
A thread is the execution unit of a process.
2. Thread status: new ecology; Ready state; Operating state; Blocking state; Dead state
3.start and run methods: when the thread starts a new task, we call the start method to let the cpu execute the run method. We only need to call the start method to tell the cpu that it is ready.
4. There are two ways to create threads:
Inherits the Thread class. Override run method
Implement the Runnable interface to create a thread
5.sleep() method: make the current thread give up the cpu and allow a certain time for other threads to execute.
Note that when you call the sleep method, you should handle exceptions
6. Set thread priority setPriority:
Setting the priority only increases the probability that this thread can grab the cpu time slice, but it does not mean that it can grab the cpu time slice. The value is [0,10], and the default is 5
7. Thread comity: it means that the thread in the current running state releases its cpu resources, returns to the ready state from the running state, and then starts to grab the cpu time slice together with another thread. It is not certain who will grab it
8. Critical resource grabbing: resources shared by multiple threads become critical resources.
When multiple threads access critical resources at the same time, problems may occur.
9. In order to solve the problem of critical resources, locks appear. When a thread accesses critical resources, it locks the previous thread, and other threads wait first. After the previous thread releases the lock, other threads can operate critical resources.
There are two ways to lock synchronized:
Synchronized code block: add the synchronized modifier to the code block
Synchronous method: add the synchronized modifier to the class method
10. Deadlock
11. The deadlock solution uses the wait method, and the wake-up wait uses the notify and notifyAll methods

1, Thread Foundation

1. Several important concepts:

Program: it can be understood as a set of static code
Process: an ongoing program that runs static code
Thread: executing a small unit in a program
A thread is a small unit in a process.

2. Take an example to understand:

dinner party
Before the dinner, the class cleaned up.
Cleaning needs to assign tasks. Write the tasks on paper and make a list. This is a static.
At the command, start cleaning. Class cleaning is the process.
Each student does his own things and executes them concurrently without affecting each other.

3. How to create threads in Java: let threads execute and multithread

Master several different states of each thread and how to switch between states:

How to implement threads
Customize a class
Implementing Runnable by inheriting Thread
Override run method
Call the start method to make the Thread enter the ready state. Note that the start method is in the Thread class

4. The process of implementing threads

1. Describe a class yourself
2. Inherit the parent class Thread
3. Rewrite the run method
4.new a thread object calls the start() method to make the thread enter the ready state

Realize a small example of running
Multiple people running at the same time: Su Bingtian; Bolt; Justin Gatlin

//A class that inherits threads
public class RunningMan extends Thread {
    private String name;
    
    //Construction method, two, which one you want to use, which one you want to use.
    public RunningMan(){}
    public RunningMan(String name){
        this.name=name;
    }
    
    //Override run method
    public void run(){
        for(int i=1;i<=100;i++){
            System.out.println(this.name+"Run to No"+i+"Mi La");
        }
    }
}

The main method tests:

public class TestMain {
    public static void main(String[] args){
        //1. Create a thread object
        RunningMan r1 = new RunningMan("Su Bingtian");
        RunningMan r2 = new RunningMan("Bolt");
        RunningMan r3 = new RunningMan("Justin Gatlin");
        //2. Call the start method to make the thread enter the ready state and execute one by one in order
        r1.start();//Method inherited from Thread class
        r2.start();
        r3.start();
        //If run is lost, it is a single thread and executed in order.
        //We call stat to tell the thread that we are ready to let the cpu run itself.
    }
}

The implementation process is very simple, but is there any problem?

Inheritance in Java, single inheritance
extends
Person extends Animal
I want people to multithread, but I find that java is single inheritance. People have inherited animals, so they can't inherit threads anymore. So how to multithread? So there is a second kind, multithreading.

5. Another method and process of implementing threads

1. Describe a class yourself
2. Implement a parent interface Runnable
3. Rewrite the run method
4.new a thread object needs to create Thread to wrap its object and call start().

public class RunningMan implements Runnable {
    private String name;
    public RunningMan(){}
    public RunningMan(String name){
        this.name=name;
    }
    //Override run method
    public void run(){
        for(int i=1;i<=100;i++){
            System.out.println(this.name+"Run to No"+i+"Mi La");
        }
    }
}

Main method

public class TestMain {
    public static void main(String[] args){
        //1. Create a thread object
        RunningMan r1 = new RunningMan("Su Bingtian");
        RunningMan r2 = new RunningMan("Bolt");
        RunningMan r3 = new RunningMan("Justin Gatlin");
        //2. Call the start method to make the thread enter the ready state and execute one by one in order
        //We have to call start, but not the thread does not have start, so we build a thread object.
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        Thread t3 = new Thread(r3);
        t1.start();
        t2.start();
        t3.start();
   }
}

2, Thread production consumer model

1. Thread safety problems may occur when threads access concurrently

Production consumer model. Producers store their products in the warehouse, consumers consume their products, and take products from the warehouse. Three categories are needed, warehouse, consumer and producer.
I want to verify whether there will be resource grabbing because consumers access the warehouse through multiple threads.

Warehouse type:

public class Warehouse { 

    //The collection in the warehouse stores elements
    private ArrayList<String> list = new ArrayList<>();
    
    //Method for adding elements to a collection
    public void add(){
        if(list.size()<20) {
            list.add("a"); //If there are enough 20 elements in the warehouse, there will be no more elements in it.
        }else{
            return;//Let the method execution end here     
         }      
     }
     
    //Method to get elements from a collection
    public void get(){
        if(list.size()>0) {
            list.remove(0); //Take the element
        }else{
            return;//Set cross-border problem
        }
     }
     
}

Producer class: because the producer is produced by multithreading, it should inherit Thread.

public class Producer extends Thread {

    //To ensure that producers and consumers use the same warehouse object, add an attribute
    private Warehouse house;
    public Producer(Warehouse house){
        this.house=house;
    }
    
    //The producer's run method keeps adding elements to the repository
    public void run(){
    //Method rewriting requires that the name and parameter list must be consistent, so parameters cannot be passed, so we can consider putting house in the attribute.
        while(true){ //Dead cycle, keep putting it in
            house.add(); 
            System.out.println("The producer deposited a good");
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

consumer:

public class Consumer extends Thread{

    //To ensure that producers and consumers use the same warehouse object, add an attribute
    private Warehouse house;
    public Consumer(Warehouse house){
        this.house=house;
    }
    
    //The consumer's method has been to get elements from the warehouse
    public void run(){
        while(true){
            house.get();
            System.out.println("The consumer took a piece of goods");
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Multithreading concurrency is likely to take both elements, and resource robbery is likely to occur.

This method in the lower right corner may cause thread safety problems. There is only one inventory left. The two consumers just judge that there are files in the warehouse and take the files together at the same time, but there is only one file, so an exception will occur. That is, threads are unsafe.

Write a main method to test:

public class TestMain {
    public static void main(String[] args){
        Warehouse house = new Warehouse();//There is an ArrayList thread inside, which is not safe
        Producer p = new Producer(house);
        Consumer c1 = new Consumer(house);
        Consumer c2 = new Consumer(house);
        //The above three threads
        p.start();
        c1.start();
        c2.start();
    }
}

When running, an exception occurs. It shows that there is no error in the analysis just now. Multithreading concurrency can cause security problems.

This model successfully demonstrates the problem of thread safety
When two consumers access the same warehouse object at the same time, there is only one element in the warehouse
The concurrent access of two consumers may cause the problem of seizing resources

2. Solve the thread safety problem yourself

  • When the warehouse object is accessed by the thread, the warehouse object is locked;
  • Warehouse objects can only be accessed by one thread, and other threads are waiting.
  • Use the feature modifier synchronized, also known as thread safety lock, synchronization, and only one thread can access at a point in time.
  • There are two forms:
    1. Place the synchronized keyword on the structure of the method
    public synchronized void get(){}
    Locked is the object that called the method
    2. Put the synchronized keyword inside the method (construction method block)
public void get(){
   A lot of code
   synchronized(Objects, writing this That's all){
    A lot of code  //Only this sentence is more important. The object is locked only when this code is executed.
   }
   A lot of code
     }

So modify the warehouse class:

public class Warehouse {
    //Singleton design pattern
    //The collection in the warehouse stores elements
    private ArrayList<String> list = new ArrayList<>();
    //Method for adding elements to a collection
    public synchronized void add(){
        if(list.size()<20) {
            list.add("a");
        }else{
            //return;// Let the method execution end here
        }
    }
    //Method to get elements from a collection
    public synchronized void get(){
        if(list.size()>0) {
            list.remove(0);//Set cross-border problem
        }else{
            //return;
            try {
                this.notifyAll();
                this.wait();//The warehouse object calling wait is not a warehouse object, waiting for the consumer thread accessing the warehouse to enter the waiting state
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3. We don't think return is very good

For producers, if the production exceeds 20, they are not no longer producing, but wait for a while and continue to produce, so it is not good to return directly.
For consumers, when they find that the quantity is 0, they don't take it anymore, but wait a while and take it again, so return is not good.

  • The different states of the thread should be toggled back and forth
    Execution wait execution wait
  • wait(); Methods in object class
    Object. wait(); Not the current object wait
    Is the thread wait that accesses the current object
    Replace the return with the following code:
		try {
              this.wait();//The warehouse call wait is not a warehouse object, waiting for the producer thread accessing the warehouse to enter the waiting state
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

But this alone will produce a state similar to suspended animation
All threads enter the waiting state, and no thread does anything. So you can use the notify method below.

  • Methods in the notify and notifyAll Object classes
    The code is:
       try {
                this.notifyAll();
                this.wait();//The warehouse call wait is not a warehouse object, waiting for the producer thread accessing the warehouse to enter the waiting state.
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

However, awakening awakens both consumers and producers. We are still not sure which one of producers and consumers starts first. We want producers to start first, but this is not something we can decide. Therefore, consider setting priorities as follows:

  • p.setPriority(10); p.getPriority();
public class TestMain {
    public static void main(String[] args){
        Warehouse house = new Warehouse();//There is an ArrayList thread inside, which is not safe
        Producer p = new Producer(house);
        //Set thread priority 1-10
        p.setPriority(10); //Give producers a higher level and give priority to resources.
        Consumer c1 = new Consumer(house);
        Consumer c2 = new Consumer(house);
        p.start();
        c1.start();
        c2.start();
    }
}

Written test questions

  • Differences between program process and thread concept
  • How threads are created
  • How to switch several states of threads
  • sleep method; Differences between wait methods:
    1. Class: Thread class; Object class
    2. Call: static class name; Object
    3. Understand: which position calls which thread to wait; Object calls methods to access other threads of the object
    4. Awakening: no need for others; Other objects are required to call notify wake up
    5. Lock: the lock will not be released; The lock will be released after waiting

3, join method & deadlock & Timer

1.join method:

Design a model
1. Two threads, one two, are added to one
2. When designing the model, the two threads are created in the run of one to ensure that the two are in order
3.two.join(); No parameter 0 with parameter 2000

A runs a few steps, B runs a few steps, then meets the single wooden bridge, and then lets B cross the single wooden bridge first.


However, in the past, we could only let the thread enter the ready state and could not control the sequence of threads. Now, we want A to join thread B. what should we do?

Thread 1:

public class ThreadOne extends Thread {
    public void run(){
        System.out.println("thread-one start");
        ThreadTwo two = new ThreadTwo();
        two.start();//When a thread is running, the second-line process is created
        //Therefore, one thread should execute earlier than two threads and control the order.
        try {
            two.join();//Thread 2 joins thread 1
            //If you fill in a time, one thread will wait for such a long time and execute, regardless of whether the two threads have finished executing or not
          //  two.join(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }//One thread waited for two threads, and the two threads rested for 5000ms
        System.out.println("thread-one end");
    }
}

Thread 2:

public class ThreadTwo extends Thread {
    public void run(){
        System.out.println("thread-two start");
         try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("thread-two end");
    }
}

So the main method

public class TestMain {
    public static void main(String[] args){
        ThreadOne one = new ThreadOne();
        one.start();
    }
}

result:
thread-one start
thread-two start
thread-two end
thread-one end

In the process of two execution and one waiting, three locks the two object. What happens if one fails to push two? Will you wait there all the time?
Three:

public class ThreadThree extends Thread{

    private ThreadTwo two;
    public ThreadThree(ThreadTwo two){
        this.two=two;
    }
    
    public void run(){
        //During the execution of two, while one is waiting, three locks the two object
        System.out.println("thread-three start");
        
        synchronized(two){
            System.out.println("two is locked");
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("two is free");
        }
        System.out.println("thread-three end");
    }
}

In the overall process, the one thread executes first. When the one thread executes, a two thread is established, and then a single wooden bridge is encountered. One lets two execute first. two.join(2000), one counts here, 2000ms. It takes 5000 ms for two to execute. Two has not been executed yet. One's 2000 ms has been counted. When one wants to push two, he finds that two has been taken away and locked by three, and tow has been taken away by three eagles. So one can't push two. One is waiting here until two comes back, and then push two to continue.
Thread 2:

public class ThreadTwo extends Thread {
    public void run(){
        System.out.println("thread-two start");
        ThreadThree three = new ThreadThree(this);
        three.start();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("thread-two end");
    }
}

result:
one start
two start
three start
two join
After 2000, one wants to remove two from his thread
I found that the two object was not in my own hand because the object was locked by the three thread
one can only kick out after threee releases the two object.
result:

thread-one start
thread-two start
thread-three start
thread-two locked
thread-two end   two Although it was taken away, it was actually executed, so he finished it first, because it only needed 5000 yuan ms You can finish it. Don't lock 10000 ms´╝îtherefore two Can be executed
two is free
thread-three end
thread-one end

The synchronized lock is very powerful,
Once the object is locked and not released, other objects need to wait,
There may be a deadlock effect.

2. Deadlock


A small box with two elements. Both wanted to get things, and two. Maybe one person takes one and wants to wait for the other party to release, but the other party does not release. The phenomenon is called deadlock.

Deadlock effect
Simulate a model to demonstrate deadlock. The philosopher's dining problem, the table on the left above. There may be a deadlock, but it is also possible that some people quickly get a pair.

Only properties:

public class Chopstick {
    private int num;
    public Chopstick(int num){
        this.num=num;
    }
    public int getNum(){
        return this.num;
    }
}

Philosopher:

public class Philosopher extends Thread{

    private String pname;//Philosopher's name
    private Chopstick left;
    private Chopstick right;
    //private long time;
    
    public Philosopher(String pname,Chopstick left,Chopstick right,long time){
        this.pname = pname;
        this.left = left;
        this.right = right;
    }
    
    public void run(){
            synchronized (left) {
            System.out.println(this.pname+"Picked up the one on the left"+this.left.getNum()+"chopsticks");
            synchronized (right){
                System.out.println(this.pname+"Picked up the one on the right"+this.right.getNum()+"chopsticks");
                System.out.println(this.pname+"Began to gobble it up");
            }
        }
    }
}

Main method:

public class TestMain {
    public static void main(String[] args){
    
        Chopstick c1 = new Chopstick(1);
        Chopstick c2 = new Chopstick(2);
        Chopstick c3 = new Chopstick(3);
        Chopstick c4 = new Chopstick(4);
        
        Philosopher p1 = new Philosopher("philosopher a",c2,c1);
        Philosopher p2 = new Philosopher("philosopher b",c3,c2);
        Philosopher p3 = new Philosopher("philosopher c",c4,c3);
        Philosopher p4 = new Philosopher("philosopher d",c1,c4);
        
        p1.start();
        p2.start();
        p3.start();
        p4.start();
    }
}
//There may be a deadlock. One person gets a chopstick, but there may be no problem of life and death. Someone takes it fast and eats a meal.

To solve the deadlock problem:
1. Comity ----- > time difference
2. Do not create problems with common objects

Philosophers:

public class Philosopher extends Thread{
    private String pname;//Philosopher's name
    private Chopstick left;
    private Chopstick right;
    private long time; //Come up and get some sleep
    public Philosopher(String pname,Chopstick left,Chopstick right,long time){
        this.pname = pname;
        this.left = left;
        this.right = right;
        this.time = time;
    }
    public void run(){
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (left) {
            System.out.println(this.pname+"Picked up the one on the left"+this.left.getNum()+"chopsticks");
            synchronized (right){
                System.out.println(this.pname+"Picked up the one on the right"+this.right.getNum()+"chopsticks");
                System.out.println(this.pname+"Began to gobble it up");
            }
        }
    }
}

Main method:

public class TestMain {
    public static void main(String[] args){
        Chopstick c1 = new Chopstick(1);
        Chopstick c2 = new Chopstick(2);
        Chopstick c3 = new Chopstick(3);
        Chopstick c4 = new Chopstick(4);
        Philosopher p1 = new Philosopher("philosopher a",c2,c1,0);
        Philosopher p2 = new Philosopher("philosopher b",c3,c2,3000);
        Philosopher p3 = new Philosopher("philosopher c",c4,c3,0);
        Philosopher p4 = new Philosopher("philosopher d",c1,c4,3000);
	//People on the opposite side can eat at the same time, so they can set the same sleeping time.

        p1.start();
        p2.start();
        p3.start();
        p4.start();
    }
}

Tags: thread

Posted on Wed, 01 Dec 2021 11:29:02 -0500 by shatztal