day-22 deadlock, thread communication, singleton mode, thread pool

Posted by MemphiS on Wed, 26 Jan 2022 07:13:11 +0100

1 deadlock
That is, in the process of execution, the other party enters the locking method, resulting in a state that everyone can't access

Deadlock principle:

1 when a thread completes execution, it needs to nest and lock two objects successively. In this process, the first object is locked first

2 another thread, after the execution is completed, nested successively, locked and executed two objects, and in this process, locked the second object first

3 when the first thread executes to the second object, it is found that it has been locked and can only wait

4 when the second thread executes to the first object, it is found that it has been locked and can only wait

public static void main(String[] args){
		Object o1 = new Object();
		Object o2 = new Object();
		Thread t1 = new Thread(new A1(o1,o2));
		Thread t2 = new Thread(new A2(o1,o2));
		t1.setName("t1");
		t2.setName("t2");
		t1.start();
		t2.start();
	}
}
class A1 implements Runnable{
	Object o1;
	Object o2;
	public A1(Object o1, Object o2) {
		super();
		this.o1 = o1;
		this.o2 = o2;
	}
	@Override
	public void run() {
		synchronized(o1){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized(o2){
				System.out.println(Thread.currentThread().getName()+"Execution complete");
			}
		}	
	}
}
class A2 implements Runnable{
	Object  o1;
	Object  o2;
	public A2(Object o1, Object o2) {
		super();
		this.o1 = o1;
		this.o2 = o2;
	}
	@Override
	public void run() {
		synchronized(o2){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized(o1){
				System.out.println(Thread.currentThread()+"Execution complete");
			}
		}
		
	}

2 thread communication

wait: letting the thread enter the waiting state will release the held lock

No parameter or passing in 0 means that you have been waiting and will not wake up automatically. You can only wait for notify to wake up

You can also pass in a value of type long, which is similar to waking up when sleep # time comes

notify: randomly wakes up a thread waiting in the object

notifyAll: wakes up all waiting threads in this object

The above methods can only be used in locked member methods

Usage: such as printing odd and even numbers

public class Thread_02_wait {
		public static void main(String[] args){
			Num num = new Num();
			Thread t1 = new PrintEven(num);
			Thread t2 = new PrintOdd(num);
			t1.setName("t1");
			t2.setName("t2");
			t1.start();
			t2.start();
		}
}
//Print even numbers
class PrintEven extends Thread{
	Num num;

	public PrintEven(Num num) {
		super();
		this.num = num;
	}
	@Override
	public void run(){
		while(true){
			num.printEven();
		}
	}
}
//Print odd
class PrintOdd extends Thread{
	Num num;

	public PrintOdd(Num num) {
		super();
		this.num = num;
	}
	@Override
	public void run(){
		while(true){
			num.printOdd();
		}
	}
}
class Num{
	int count = 1;
	public synchronized void printOdd(){
		System.out.println(Thread.currentThread().getName()+"--->"+count);
		count++;
		//Wake up other threads and take the print even number
		this.notifyAll();
		//Enter waiting
		try {
			Thread.sleep(500);
			this.wait();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	public synchronized void printEven(){
		System.out.println(Thread.currentThread().getName()+"-->"+count);
		count++;
		//Wake up other threads and print odd numbers
		this.notifyAll();
		//Enter waiting
		try {
			Thread.sleep(500);
			this.wait();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}

3 producers and consumers

package Day2;

import java.util.Random;

/**
 * Producer consumer
 * 1 Define a business class SynStack, in which there is a variable to save the number of generated elements
 * 2 There is a char array in the business class, which is used to save the elements of production (if only a-z is produced)
 * 3 There need to be two methods in the business class: one is production push and the other is consumption pop
 * 						push Method is mainly used to add data to the array
 * 										Number + 1, and judge whether it is full. When it is full, suspend entry and wait
 * 						pop Method is mainly used to fetch the data in the array
 * 										The number is - 1. It is also necessary to judge whether the consumption is finished. When it is finished, hang up and wait
 * @author Tian Biao
 * @Date 2022 January 25, 2014 - 6:29:50 PM
 */
public class Thread_03 {
		public static void main(String[] args){
			SynStack1 ss =new SynStack1();
			Thread p = new Thread(new Producer(ss));
			Thread c = new Thread(new Consumer(ss));
			p.start();
			c.start();
		}
 }
class Producer implements Runnable{
	SynStack1 ss;

	public Producer(SynStack1 ss) {
		super();
		this.ss = ss;
	}

	@Override
	public void run() {
		Random random = new Random();
	while(true){
		char ch =(char)(random.nextInt(26)+97);
		ss.push(ch);
	}
		
	}
}
class Consumer implements Runnable{
	SynStack1 ss;

	public Consumer(SynStack1 ss) {
		super();
		this.ss = ss;
	}

	@Override
	public void run() {
		while(true){
		try {
			Thread.sleep(600);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		ss.pop();
	}
}
}
class SynStack1{
	//Container for saving data
	char[] data = new char[6];
	//Number of production
	int count = 0;
	//production
	public synchronized void push(char ch){
		//Judge whether it is full
		if(count == data.length){
			try{
				this.wait();
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
		// Here, it means that it is not full and production begins
		//Awaken consumer consumption
		this.notifyAll();
		data[count] = ch;
		count++;
		System.out.println("Produced" +ch +",surplus"+count+"Elements");
	 }
	public synchronized char pop(){
		 //Judge whether it is empty
		if(count == 0){
			try{
				//There is no need to wake up the producer, because the producer is full and waiting is empty, indicating that the producer must not have a wait
				this.wait();
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
		//Here it means that it is not empty and start consumption
		count--;
		char ch = data[count];
		//Wake up producers
		this.notifyAll();
		System.out.println("Consumption" +ch+",surplus" +count +"Elements");
		return ch;
	}
	
}

4. Singleton mode

Let a class instantiate only one object

The construction method is privatized, the static variable saves the object, and the public static method is used to obtain the class object

Hungry man safety mode

public class Thread_04 {
	private Thread_04(){
		
	}
	//hungry man
	private static Thread_04 singLeton = new Thread_04();
	public static Thread_04 getInstance() {
		return singLeton;
	}
}

Lazy safety mode

public class Thread_05 {
	private  Thread_05(){
		
	}
//	private  static  Thread_05 singLeton = null;
//	//Inefficient, because you need to queue every time
//	public synchronized static Thread_05 getInstance(){
//		if(singLeton == null){
//			singLeton = new Thread_05();
//		}
//		return singLeton;
//		
//	}
	//volatile: add it to prevent instruction rearrangement
	private volatile static  Thread_05 singLeton = null;
	//It is more efficient because it only needs to queue for the first time
	public  static Thread_05 getInstance(){
		//Double check
		if(singLeton == null){
			synchronized(Thread_05.class){
				if(singLeton == null){
			singLeton = new Thread_05();
		}
		}
		}
		return singLeton;
		
	}
}

5 line pass pool

Background: resources that are often created and destroyed and use a large amount of resources, such as single thread under concurrent conditions, have a great impact on performance

Idea: create many threads in advance, put them into the thread pool, get them directly when using them, and put them back into the pool after using them, so as to avoid frequent creation and destruction and realize reuse

Benefits:

a improve response speed (reduce the time to create new threads)

b reduce resource consumption (reuse threads in the thread pool and do not need to be created every time)

c facilitate thread management

corePoolSize: the size of the core pool

maximumPoolSize: maximum number of threads

keepAliveTime: when the thread has no task, how long will it last at most and then terminate

6 thread pool API

ExecutorService: real thread pool interface # common subclass: ThreadPoolExecutor

Executors: tool class, factory class of thread pool. Used to create and return different types of thread pools

7 role of thread pool

Limit the number of execution threads in the system

According to the environment of the system, the number of threads can be set automatically or manually to achieve the best running effect

Less waste of system resources, more system congestion and low efficiency

Why use thread pool

1. The number of threads created and destroyed is reduced. Each working thread can be reused and can perform multiple tasks

2. You can adjust the number of working threads in the thread pool according to the bearing capacity of the system to prevent the server from getting tired due to excessive memory consumption (each thread needs about 1MB. The more threads are opened, the more memory will be consumed, and finally crash)

Topics: Java