Basic concept of java Concurrent 01- thread

Posted by boofboof on Thu, 10 Feb 2022 17:27:49 +0100


Basic concept of thread:

Threads are different execution paths of the system. The following is an execution path:

Each branch is a thread, and the program written before is a branch.
Process: a program is a process that puts code into the code area, which is called a process
Operating system scheduler
Thread is a dynamic concept: multiple execution paths within a process
The actual running in the machine are threads
The machine can execute multiple threads at the same time. Windows supports multiple threads and multiple processes (DOS is a single process)
In fact, the CPU executes multiple threads in rotation, which is faster, so it can be regarded as that the CPU executes multiple threads at the same time
But at a certain point in time, the CPU can only execute one thread
If there are multiple CPU s, you can really execute multithreading
Note that the CPU time slice is not necessarily average. Maybe this thread has more time and the other thread has less time.
The threads of a process share memory units (process exclusive memory), which will lead to conflict and concurrency problems.


The essential difference between process and thread is that each process has its own set of variables, while threads share data

How to create a thread:

##Runnable interface

  1. Customize a thread to implement the run method of the Runnable interface
    The run method is the content to be executed and will be executed on another branch
    The Thread class itself also implements the Runnable interface
  2. In the main method, new a custom thread object, and then new a thread class object. The parameters of its construction method are custom Thread objects
    (this object implements the run method, and Thread also implements the run method, so this is a method rewrite)

    The parameter type is the Runnable interface, which also accepts its subclasses (custom Thread objects)
    (there is a polymorphic process when the parent class reference points to the child class object)
  3. Execute the start method of Thread class, and the Thread starts to execute
    Since then, branches have been generated. One branch will execute the run method. In the main method, it will not wait for the run method to return after calling, but directly continue to execute. It is the second branch. The two branches run in parallel
    When outputting, one branch will be executed for a while, and then another branch will be executed for a while (consistent with the working mode of Cpu)
    If you do not call the start method with a new Thread object, you can directly call the run method of the custom Thread
    So it's just a method call, and it's still a single thread, not a multi-threaded parallel execution

① Customize a class MyThread to implement the run method implements Runnable of the Runnable interface
② In the main method, create a custom class new MyThread mt
(3) in the main method, new is a Thread class. Its construction method parameter is the object of the custom class, then calls the start method (automatically calling the run method).
Written on one line is thread t = new thread (New mythread()) start();
Example:

public class test {
	public static void main(String []args){
		Runner r = new Runner();
		Thread t = new Thread(r);
		t.start();
		for(int i = 0; i <100;i++){
			System.out.println("Main " +i);
		}
	}
}
class Runner implements Runnable {
	public void run (){
		for(int i = 0; i<100; i++){
			System.out.println("Runner"+i);
		}
	}
}

Output result:

Two threads execute alternately
In fact, the static proxy mode is adopted
definition
Proxy Pattern is a structural pattern of objects. Proxy Pattern provides a proxy object for an object, and the proxy object controls the reference to the original object.
The agent mode will not change the original interface and behavior, but transfer the agent to do something, and the agent can control the original goal. For example, the agent will only buy things, but will not change the behavior and will not make things.
classification
Static agent and dynamic agent

Interface

package com.liang.pattern;  
public interface UserManager {  
    public void addUser(String userId,String userName);  
    public void delUser(String userId);  
    public void modifyUser(String userId,String userName);  
    public String findUser(String userId);  
}  

Target object

package com.liang.pattern;  
public class UserManagerImpl implements UserManager {  
    public void addUser(String userId, String userName) {  
        try{  
            System.out.println("UserManagerImpl.addUser() userId-->>" + userId);  
        }catch(Exception e){  
            e.printStackTrace();  
              
            throw new RuntimeException();  
        }  
    }  
  
    public void delUser(String userId) {  
        System.out.println("UserManagerImpl.delUser() userId-->>" + userId);  
    }  
    public String findUser(String userId) {  
        System.out.println("UserManagerImpl.findUser() userId-->>" + userId);  
        return "Yu Liang";  
    }  
    public void modifyUser(String userId, String userName) {  
        System.out.println("UserManagerImpl.modifyUser() userId-->>" + userId);  
    }  
}  

For the proxy class, we use the proxy object to do some logging, and we print the brief information to the console.

package com.liang.pattern;  
  
public class UserManagerImplProxy implements UserManager {  
    private UserManager userManager;  
    public UserManagerImplProxy(UserManager userManager){  
        this.userManager = userManager;  
    }  
    public void addUser(String userId, String userName) {  
                //Record log and other operations or print input parameters  
        System.out.println("start-->>addUser() userId-->>" + userId);  
        try{  
            userManager.addUser(userId, userName);  
                //Execute successfully, print success information  
            System.out.println("success-->>addUser()");  
        }catch(Exception e){  
            e.printStackTrace();  
                //In case of failure, print the failure information  
            System.out.println("error-->>addUser()");  
            //throw new RuntimeException();  
        }  
    }  
  
    public void delUser(String userId) {  
        //Ibid., omitted  
        userManager.delUser(userId);  
    }  
  
    public String findUser(String userId) {  
        //Ibid., omitted  
        userManager.findUser(userId);  
        return null;  
    }  
  
    public void modifyUser(String userId, String userName) {  
        //Ibid., omitted  
        userManager.modifyUser(userId, userName);  
          
    }  
}  

Client call

package com.liang.pattern;  
public class Client {  
  
    public static void main(String[] args) {  
        UserManager userManager = new UserManagerImplProxy(new UserManagerImpl());  
        userManager.addUser("001","sure");  
    }  
}   

Output the result, and the method is executed successfully
start–>>addUser() userId–>>001
UserManagerImpl.addUser() userId–>>001
success–>>addUser()

From the class diagram, we can see that the client can directly deal with the target object, and an indirect layer is added in the middle of the agent. Their functions are the same and their parameters are not changed.

Advantages and disadvantages
advantage:
1. Intuitively, static agents are real, and we write them ourselves.
2. Add in the compilation period, and specify who calls who in advance, which is efficient.

Disadvantages:
Similarly, its advantages have become its fatal disadvantages.
1. Static proxy is very troublesome and requires a large number of proxy classes. When we have multiple target objects that need proxy, I need to establish multiple proxy classes and change the original code. If we change too much, there is likely to be a problem and we must retest.
2. Repeated code will appear in every corner, which violates a principle: repetition is not a good taste. We should eliminate repetition again and again.
3. The flexibility of the system is poor when it is added in the compilation period

In fact, method 1 adopts the static proxy mode
Both the Thread class and the custom Thread class implement the Runnable interface
Thread class is Proxy, and custom thread class is proxied
Thread construction method

By calling the start method of Thread, you actually call the start method of custom Thread class (of course, there are other codes in addition)
##Inherit Thread class
① Customize a class MyThread, inherit the Thread class, and override the run method
② Create a custom class in the main method, and then call the start method directly

public class test {
	public static void main(String []args){
		Runner r = new Runner();
		r.start();
		for(int i = 0;i <100;i++){
			System.out.println("Main"+i);
		}
	}
}
class Runner extends Thread {
	public void run (){
		for(int i = 0; i<100;i++){
			System.out.println("Runner"+i);
		}
	}
}

Compared with the two methods, the second method has less code
However, the first method is more flexible. The custom Thread class can also inherit other classes, not limited to the Thread class
It is recommended to use interfaces to implement multithreading (the first method)

##Implement Callable


Type parameter:
V - result type of call method (return value type)
Tasks that return results and may throw exceptions. The implementer defines a method called call without any parameters.


The Executor provides methods to manage termination and generate Future for tracking the execution status of one or more asynchronous tasks.
ExecutorService can be closed, which will cause it to reject new tasks. Two methods are provided to close ExecutorService. The shutdown() method allows the execution of previously submitted tasks before termination, while the shutdown now () method prevents waiting for the task to start and trying to stop the currently executing task. At the time of termination, the executor has no task executing or waiting for execution, and cannot submit a new task. Unused executorservices should be closed to allow recycling of their resources.
The method to obtain the ExecutorService instance needs the help of the static method of the Executors class


Type parameter:
V - the result type returned by the get method of this Future (need to be specified)
Future represents the result of asynchronous calculation. It provides a method to check whether the calculation is completed, so as to wait for the completion of the calculation and obtain the results of the calculation. After the calculation is completed, you can only use the get method to obtain the results. If necessary, you can block this method before the calculation is completed.

You can get the Future object through the submit method of ExecutorService.

The parameter of the submit method is the object of the custom process class
Then call the get method of the Future interface to get the return value object.

If you want to stop the thread, call the ExecutorService's shutdown now method

Even if the code of the run method is executed, if the shutdown now method is not called, the thread still does not stop.
Using method 1, the thread ends when the code is executed
Example: Tortoise rabbit race:

public class T1 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		Race bunny = new Race("rabbit",300);
		Race tortoise = new Race("turtle",1000);
		ExecutorService es = Executors.newFixedThreadPool(2);
		Future<Integer> result1 = es.submit(bunny);
		Future<Integer> result2 = es.submit(tortoise);
		
		Thread.sleep(2000);
		bunny.setFlag(false);
		tortoise.setFlag(false);
		
		int bunnySteps = result1.get();
		int tortoiseSteps = result2.get();
		System.out.println("The rabbit ran away"+bunnySteps+"step");
		System.out.println("The tortoise ran away"+tortoiseSteps+"step");
		
		es.shutdownNow();
	}
}

class Race implements Callable<Integer>{
	private String name;
	private int step;
	private int time = 0 ;
	private boolean flag = true;
	
	public Integer call() throws Exception {
		while(flag){
			Thread.sleep(time);
			step++;
		}
		return step;
	}

	public Race() {
	}

	public Race(String name, int time) {
		this.name = name;
		this.time = time;
	}
}

Topics: Java Back-end Multithreading thread pool