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)