1 multithreading overview
What are processes and threads?
A process is an application (a process is a software). A thread is an execution scenario / execution unit in a process. A process can start multiple threads.
For example:
For java programs, when entering in the DOS command window:
After entering java Helloworld.
The JVM will be started first, and the JVM is a process. The JVM starts another main thread to call the main method. At the same time, start a garbage collection thread to take care of and collect garbage. At the very least, there are at least two concurrent threads in current java programs, one is the garbage collection thread, and the other is the main thread executing the main method.
What is the relationship between process and thread?
for instance
Alibaba: process
Ma Yun: a thread of Alibaba, Tong Wenhong: a thread of Alibaba
JD: process
Qiang Dong: a thread of JD. Mei Mei: a thread of JD
Process can be seen as a real-life company. Thread can be regarded as an employee in the company.
be careful:
The memory of process A and process B is independent and not shared. (Alibaba and JD will not share resources). Warcraft game is A process and cool dog music is A process. The two processes are independent and do not share resources.
What about thread A and thread B?
In the java language: thread A and thread B, heap memory and method area memory are shared. However, the stack memory is independent, one thread and one stack.
What about thread A and thread B?
In the java language: thread A and thread B, heap memory and method area memory are shared. However, the stack memory is independent, one thread and one stack.
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (IMG khkimwhb-1635520552477)( https://i.loli.net/2021/10/20/Ii1TtLExcWaUupG.png )]
Assuming that 10 threads are started, there will be 10 stack spaces. Each stack and each stack do not interfere with each other and execute their own, which is multi-threaded concurrency.
The railway station can be regarded as a process. In the railway station, every ticket window can be regarded as a thread. I buy tickets in window 1 and you can buy tickets in window 2. You don't need to wait for me and I don't need to wait for you.
Therefore, multithreading concurrency can improve efficiency.
The reason why there is multithreading mechanism in java is to improve the processing efficiency of the program.
Think about a question:
After using the multithreading mechanism, the main method ends. Is it possible that the program will not end.
The main method ends, but the main thread ends, the main stack is empty, and other stacks (threads) may still press the stack.
Analyze a problem:
For a single core cpu, can you really achieve real multithreading concurrency?
For multi-core cpu computers, real multithreading concurrency is no problem. 4-core cpu means that four processes can execute concurrently at the same time point.
What is true multithreading concurrency?
The t1 thread executes t1. The t2 thread executes t2. t1 does not affect t2, and t2 does not affect t1. This is called true multithreading concurrency.
Single core CPU means that there is only one brain, which can not achieve real multithreading concurrency, but it can give people a feeling of multithreading concurrency.
For a single core CPU, it can only handle one thing at a certain point in time. However, due to the extremely fast processing speed of the CPU and frequent switching between multiple threads, it feels like: multiple things are being done at the same time!!!
Thread A: play music, thread B: run the Warcraft game. Thread A and thread B frequently switch execution. Humans will feel that the music is playing all the time and the game is running all the time, giving us the feeling that it is concurrent at the same time.
Cinemas use film to play movies. When the speed of film playing reaches a certain level, human eyes have an illusion that they feel animated. This shows that the human response speed is very slow, just like a steel needle sticking into his hand and finally feeling pain. This process takes a "long" time. During this period, the computer can cycle hundreds of millions of times. So the execution speed of the computer is very fast.
test
After analyzing the following program, there are several threads, except the garbage collection thread. How many threads are there?
package com.thread; /* Let's analyze the following program. There are several threads, except garbage collection threads. How many threads are there? 1 Threads (because there is only one stack) */ public class ThreadTest01 { public static void main(String[] args) { System.out.println("main begin"); m1(); System.out.println("main finish"); } private static void m1() { System.out.println("m1 begin"); m2(); System.out.println("m1 finish"); } private static void m2() { System.out.println("m2 begin"); m3(); System.out.println("m2 finish"); } private static void m3() { System.out.println("m3 execute!"); } }
principle
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-dcdbisxv-1635520552487)( https://i.loli.net/2021/10/20/Y4MwgXQkcyaA6rq.png )]
2 thread implementation
The eternal rule in Java: the code in the method body is executed line by line from top to bottom. The above is not over, and the following will never be executed
java supports multithreading mechanism. And java has implemented multithreading. We just need to inherit.
Method 1
The first way: write a class, directly inherit java.lang.Thread, and rewrite the run method.
package com.thread; public class ThreadTest02 { public static void main(String[] args) { //Here is the main method. The code here belongs to the main thread and runs in the main stack. //Create a new branch thread object MyThread myThread = new MyThread(); //Start thread //The function of the start() method is to start a branch thread and open up a new stack space in the JVM. After the code task is completed, it ends instantly, //The task of this code is to open a new stack space. As long as the new stack space is opened, the start() method ends. The thread starts successfully. //The thread that starts successfully will automatically call the run method, and the run method is at the bottom of the branch stack (pressing the stack). //The run method is at the bottom of the branch stack and the main method is at the bottom of the main stack. Run and main are equal. myThread.start(); //This code quickly opens up the stack space, ends at once and starts concurrency //Calling the run() method directly will not start a new thread //myThread.run();// This is single threaded //The code here still runs in the main thread. for (int i = 0; i < 1000; i++) { System.out.println("Main thread---->"+i); } } } class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println("Branch thread---->"+i); } } }
Program output comes first and then, how much and how little
Main thread ----- > 893
Main thread ----- > 894
Branch thread ----- > 863
Main thread ----- > 895
Main thread ----- > 896
Main thread ----- > 897
Branch thread ----- > 864
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (IMG iuacvekr-1635520552490)( https://i.loli.net/2021/10/20/274QnmcMxg9A31r.png )]
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-lo5wsuf3-1635520552492)( https://i.loli.net/2021/10/20/Na58zS2LxV7w3gq.png )]
Method 2
The second way: write a class to implement the java.lang.Runnable interface and the run method.
package com.thread; public class ThreadTest03 { public static void main(String[] args) { //Create a runnable object //MyRunnable mr = new MyRunnable(); // Encapsulate the runnable object into a thread object //Thread t = new Thread(mr); Thread t = new Thread(new MyRunnable());//Merge write t.start(); for (int i = 0; i < 100; i++) { System.out.println("Main thread---->"+i); } } } //This is not a thread class, but a runnable class. It is not yet a thread. class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("Branch thread---->"+i); } } }
**Method 2 is used more, because Java inherits from Thread class, so it cannot inherit other classes** However, the implementation interface can inherit other classes
Using anonymous inner classes
package com.thread; /* Use anonymous inner classes */ public class ThreadTest04 { public static void main(String[] args) { Thread t = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("Branch thread---->"+i); } } }); t.start(); for (int i = 0; i < 100; i++) { System.out.println("Main thread---->"+i); } } }
3 thread life cycle
- New status
- Ready status
- running state
- Blocking state
- Death state
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-ba03bctb-1635520552494)( https://i.loli.net/2021/10/20/Nc5BJsAmlKVtCPE.png )]
4 common methods of thread
Gets the current thread object
Thread t = Thread.currentThread();
Gets the name of the thread object
String name = thread object. getName("thread name");
Modify the name of the thread object
Thread object. setName("thread name");
Default thread names: Thread-0, Thread-1....
package com.thread; public class ThreadTest05 { public static void main(String[] args) { Thread tt = Thread.currentThread(); System.out.println(tt.getName()); //main MyThread2 t = new MyThread2(); String name = t.getName(); System.out.println(name); t.setName("ttttt"); System.out.println(t.getName()); MyThread2 t2 = new MyThread2(); t2.setName("hhh"); t2.start(); } } class MyThread2 extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++) { //Who started it? Who's the name Thread ttt = Thread.currentThread(); System.out.println(ttt.getName()+"---->"+i); } } }
sleep method of thread:
static void sleep(long millis)
-
Static method: Thread.sleep(1000);
-
The parameter is milliseconds
-
Function: let the current thread sleep, enter the "blocking state", give up occupying CPU time slice and let it be used by other threads.
This line of code appears in thread A, and thread A will go into sleep. If this line of code appears in the B thread, the B thread will go to sleep.
package com.thread; public class ThreadTest06 { public static void main(String[] args) { try { Thread.sleep(1000*5); } catch (InterruptedException e) { e.printStackTrace(); } //Output after 5s System.out.println("hello world"); } }
-
Thread.sleep() method can achieve this effect:
At specific intervals, execute a specific piece of code, and how often.
package com.thread; public class ThreadTest06 { public static void main(String[] args) { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"---->"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Interview questions
package com.thread; //Interview questions of sleep method public class ThreadTest07 { public static void main(String[] args) { MyThread3 t = new MyThread3(); t.start(); //Will this string of code block the branch program? //No, sleep is a static method, //Regardless of the instance name, it is still converted to Thread during execution. sleep //This will block main try { t.sleep(1000*5); System.out.println("hello world"); } catch (InterruptedException e) { e.printStackTrace(); } } } class MyThread3 extends Thread{ @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println(Thread.currentThread().getName()+"--->"+i); } } }
Wake up the thread of sleep
Note: a subclass cannot throw more exceptions than its parent class
interrupt();
package com.thread; public class ThreadTest08 { public static void main(String[] args) { Thread t = new Thread(new MyRunnable2()); t.setName("t"); t.start(); try { Thread.sleep(1000*5); } catch (InterruptedException e) { e.printStackTrace();//Comment out this line and no exception information will be printed } t.interrupt(); } } class MyRunnable2 implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"--->begin"); //A subclass cannot throw more exceptions than its parent class try { Thread.sleep(1000*60*60*24*3650); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"--->end"); } }
Force thread termination
- stop(), which is easy to lose data and outdated, is not recommended
package com.thread; public class ThreadTest09 { public static void main(String[] args) { Thread t = new Thread(new MyRunnable3()); t.setName("t"); t.start(); try { Thread.sleep(1000*5); } catch (InterruptedException e) { e.printStackTrace(); } t.stop();//Deprecated } } class MyRunnable3 implements Runnable{ @Override public void run() { for (int i = 0; i < 10; i++) { try { System.out.println(Thread.currentThread().getName()+"--->"+i); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
- Marking method
package com.thread; public class ThreadTest10 { public static void main(String[] args) { MyRunnable4 r = new MyRunnable4(); Thread t = new Thread(r); t.setName("t"); t.start(); try { Thread.sleep(1000*5); } catch (InterruptedException e) { e.printStackTrace(); } r.run = false; } } class MyRunnable4 implements Runnable{ boolean run = true; @Override public void run() { for (int i = 0; i < 10; i++) { if(run){ System.out.println(Thread.currentThread().getName()+"--->"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }else { return; } } } }
5 thread scheduling (understand)
summary
Common scheduling models:
-
Preemptive
The priority of that thread is relatively high, and the probability of grabbing CPU time slices is higher / more. Java adopts preemptive scheduling model.
-
Mean fraction
Evenly allocate CPU time slices. Each thread occupies the same length of CPU time slice. Equal distribution, all equal. In some programming languages, the thread scheduling model adopts this method
Thread scheduling method
-
Example method
void setpriority(int newPriority) sets the priority of the thread
int getPriority() get thread priority
Lowest priority 1
The default priority is 5
Highest priority 10Those with higher priority may get more cpu time slices. (but not exactly. The probability is high)
package com.thread; //thread priority public class ThreadTest11 { public static void main(String[] args) { System.out.println("Max:"+ Thread.MAX_PRIORITY); System.out.println("Min:"+ Thread.MIN_PRIORITY); System.out.println("Nor:"+ Thread.NORM_PRIORITY); //Gets the default priority of the current thread Thread currentThread = Thread.currentThread(); System.out.println(currentThread.getName()+"Default Priority "+currentThread.getPriority()); //5 Thread t = new Thread(new MyRunnable5()); t.start(); //Those with high priority will get more time slices } } class MyRunnable5 implements Runnable{ @Override public void run() { Thread cu = Thread.currentThread(); System.out.println(cu.getName()+"Default Priority "+cu.getPriority()); //5 } }
-
Static method:
static void yield() yield method
Pauses the currently executing thread object and executes other threads.The yield() method is not a blocking method. Make the current thread give way to other threads.
The execution of the yield() method will return the current thread from the "running state" to the "ready state".
Note: after returning to ready, it is possible to grab it again.
package com.thread; public class ThreadTest12 { public static void main(String[] args) { Thread t = new Thread(new MyRunnable6()); t.setName("t"); t.start(); for (int i = 1; i <= 100; i++) { System.out.println(Thread.currentThread().getName()+"---->"+i); } } } class MyRunnable6 implements Runnable{ @Override public void run() { for (int i = 1; i <= 100; i++) { if(i%10 == 0){ Thread.yield(); //The current thread pauses the following and gives up to the main thread } System.out.println(Thread.currentThread().getName()+"--->"+i); } } }
Partial output
t—>40
main---->48
main---->49
main---->50
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-62fka70f-1635520552496)( https://i.loli.net/2021/10/21/l1hqGzJtTQSfudZ.png )]
-
Merge thread
Instance method: void join()
class MyThread1 extends Thread { public void doSome(){ MyThread2 t = new MyThread2(); t.join()//The current thread enters the block, and the t thread executes until the t thread ends. The current thread can continue. } } class MyThread2 extends Thread{ }
package com.thread; //Thread merging public class ThreadTest13 { public static void main(String[] args) { System.out.println(Thread.currentThread().getName()+"--->begin"); Thread t = new Thread(new MyRunnable7()); t.setName("t"); t.start(); try { t.join(); //t merges into the current thread. The current thread is blocked. t thread executes to the end } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"--->end"); } } class MyRunnable7 implements Runnable { @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println(Thread.currentThread().getName() + "--->" + i); } } }
6 thread safety (key)
In the development, our projects are running in the server, and the server has completed the definition of thread, the creation of thread object, the startup of thread, etc. we don't need to write these codes.
The most important thing is that the program we write needs to be run in a multithreaded environment. What we need to pay more attention to is whether these data are safe in a multithreaded concurrent environment. (key: ****************************************************
Why is there a security problem
If the following three conditions are met, there is a thread safety problem.
Condition 1: multithreading concurrency.
Condition 2: there is shared data.
Condition 3: the shared data has the behavior of modification.
Multi thread concurrent money withdrawal problem
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (IMG sopxjmdr-1635520552497)( https://i.loli.net/2021/10/23/If8dBOgo6r4C1va.png )]
How to solve: thread synchronization
Threads are queued for execution and cannot be concurrent. Queuing is used to solve thread safety problems.
This mechanism is called thread synchronization mechanism
Thread synchronization is thread queuing. If threads are queued, some efficiency will be sacrificed. Data security comes first. Only when data is safe can we talk about efficiency. Data is not safe and inefficient.
Synchronous programming model and asynchronous programming model
Synchronous programming model: synchronization is queuing
When thread t1 and thread t2 execute, they must wait for the end of t2 thread execution, or when t2 thread executes, they must wait for the end of t1 thread execution. There is a waiting relationship between the two threads, which is the synchronous programming model.
Low efficiency. Threads are queued for execution.
Asynchronous programming model: asynchrony is concurrency
Thread t1 and thread t2 execute their own. t1 regardless of t2 and t2 regardless of t1, no one needs to wait for anyone. This programming model is called asynchronous programming model.
In fact, it is: multithreading concurrency (high efficiency.)
Multi thread concurrent money withdrawal problem test
package com.threadsafe1; public class Test { public static void main(String[] args) { Account act = new Account("act-001",10000); Thread t1 = new AccountThread(act); Thread t2 = new AccountThread(act); t1.setName("t1"); t2.setName("t2"); t1.start(); t2.start(); } } /* package com.threadsafe1; public class AccountThread extends Thread{ //Two threads share the same account private Account act; //Pass account object through construction method public AccountThread(Account act){ this.act = act; } public void run(){ double money = 5000; act.withdraw(money); System.out.println(Thread.currentThread().getName()+"Withdrawal of account "+ act.getActno() +" succeeded, balance "+ act.getBalance()); //run Method to perform a withdrawal operation //Assume withdrawal of 5000; } } ================================================== package com.threadsafe1; bank account public class Account { private String actno; private double balance; public String getActno() { return actno; } public void setActno(String actno) { this.actno = actno; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public Account() { } public Account(String actno, double balance) { this.actno = actno; this.balance = balance; } public void withdraw(double money){ //Balance before withdrawal double befor = this.getBalance(); //Balance after withdrawal double after = befor - money; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Update balance setBalance(after); } } */
The output is as follows
t2 To account act-001 Withdrawal succeeded, balance 5000.0 t1 To account act-001 Withdrawal succeeded, balance 5000.0
Solve the problem of multi thread concurrent withdrawal
package com.threadsafe2; public class Test { public static void main(String[] args) { Account act = new Account("act-001",10000); Thread t1 = new AccountThread(act); Thread t2 = new AccountThread(act); t1.setName("t1"); t2.setName("t2"); t1.start(); t2.start(); } } /* package com.threadsafe2; public class AccountThread extends Thread{ //Two threads share the same account private Account act; //Pass account object through construction method public AccountThread(Account act){ this.act = act; } public void run(){ double money = 5000; act.withdraw(money); System.out.println(Thread.currentThread().getName()+"Withdrawal of account "+ act.getActno() +" succeeded, balance "+ act.getBalance()); //run Method to perform a withdrawal operation //Assume withdrawal of 5000; } } =========================================== package com.threadsafe2; bank account Use thread synchronization mechanism to solve thread safety problems public class Account { private String actno; private double balance; public String getActno() { return actno; } public void setActno(String actno) { this.actno = actno; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public Account() { } public Account(String actno, double balance) { this.actno = actno; this.balance = balance; } The following lines of code must be thread queued and cannot be concurrent. After a thread finishes executing all the code here, another thread can come in. The syntax of thread synchronization mechanism is: synchronized(){ Thread synchronization code block. } synchronized The "data" passed in parentheses is quite critical. This data must be shared by multiple threads. To achieve multi-threaded queuing. synchronized The data passed in parentheses is quite critical. This data must be shared by multiple threads to achieve multi-threaded queuing. ()What does it say? It depends on which threads you want to synchronize. Suppose t1, t2, t3, t4 and t5 have 5 threads, You just want T1, T2, T3 to line up, T4 and T5 do not need to line up. What should I do? You must write a T1, T2 and T3 shared object in () Object is not shared for T4 and T5. The shared object here is the account object. The account object is shared, so this is the account object!!! How does the following code work? 1,Assuming that t1 and t2 threads are concurrent, when starting to execute the following code, there must be one after the other. 2,Suppose t1 executes first and encounters synchronized. At this time, it automatically finds the object lock of "shared object later", After it is found, it holds the lock, and then executes the program in the synchronization code block. It is always the same during the program execution The person who owns the lock. The lock will not be released until the synchronization code block code ends. 3,Assuming that t1 has occupied the lock, t2 also encounters the synchronized keyword and will also occupy the back The lock of the shared object is occupied by t1, and t2 can only wait for the end of t1 outside the synchronization code block, When t1 finishes executing the synchronization code block, t1 will return the lock. At this time, t2 finally waits for the lock, and then t2 After occupying the lock, enter the synchronization code block to execute the program. In this way, the thread is queued for execution. Here's something to note: the shared object must be selected. The shared object must be that you need to queue up Shared by these Thread objects that execute. public void withdraw(double money){ synchronized (this){ double befor = this.getBalance(); double after = befor - money; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } setBalance(after); } } } */
t1 To account act-001 Withdrawal succeeded, balance 5000.0 t2 To account act-001 Withdrawal succeeded, balance 0.0
[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-8exwkvre-1635520552499)( https://i.loli.net/2021/10/24/I8GS1TNxF7bOPCc.png )]
There are three variables in Java
-
Instance variable: in heap.
-
Static variables: in the method area.
-
Local variables: in the stack.
Among the above three variables: local variables will never have thread safety problems. Because local variables are not shared. (one thread, one stack.) local variables are in the stack. Therefore, local variables will never be shared.
The instance variable is in the heap, and there is only 1 in the heap.
Static variables are in the method area, and there is only one in the method area.
Heap and method area are shared by multiple threads, so there may be thread safety problems.
synchronized can be used on instance methods
package com.threadsafe3; /* bank account Use thread synchronization mechanism to solve thread safety problems */ public class Account { private String actno; private double balance; public String getActno() { return actno; } public void setActno(String actno) { this.actno = actno; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public Account() { } public Account(String actno, double balance) { this.actno = actno; this.balance = balance; } //synchronized can be used on instance methods //shortcoming //In this way, the lock must be this. There is no choice. It cannot be other objects, so this method is not flexible //For sub instance methods, the whole method body needs to be synchronized, which may expand the scope of synchronization for no reason, resulting in low program execution efficiency. //This method is not commonly used //advantage //Little code, Jane //This is recommended if the shared object is this and the entire method body is synchronized public synchronized void withdraw(double money){ synchronized (this){ double befor = this.getBalance(); double after = befor - money; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } setBalance(after); } } }
If local variables are used, it is recommended to use: stringBuilder.
Because there is no thread safety problem with local variables. Choose stringBuilder.
stringBuffer is inefficient.
ArrayList is non thread safe.
Vector is thread safe.
HashMap HashSet is non thread safe.
Hashtable is thread safe.
summary
synchronized can be written in three ways:
The first: synchronous code block, flexible
Synchronized (thread shared object){
Synchronization code block;
}
The second is to use synchronized on the instance method, which means that the shared object must be this, and the synchronized code block is the whole method body.
The third is to use synchronized on static methods, which means to find class locks.
There is always only one class lock. Even if 100 objects are created, there is only one class lock.
Object lock: 1 lock for 1 object, 100 locks for 100 objects. Class lock: 100 objects, or just 1 class lock.
7 interview questions
Exam1
package com.threadexam01; //Interview question: do you need to wait for doSome when the doOther method is executed //No, because the doOther method has no synchronized modifier public class Exam01 { public static void main(String[] args) throws InterruptedException { MyClass mc = new MyClass(); Thread t1 = new MyThread(mc); Thread t2 = new MyThread(mc); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000);//The function of this sleep is to ensure that the t1 thread executes first. t2.start(); } } class MyThread extends Thread { private MyClass mc; public MyThread(MyClass mc) { this.mc = mc; } @Override public void run() { if(Thread.currentThread().getName() == "t1"){ mc.doSome(); }else { mc.doOther(); } } } class MyClass { public synchronized void doSome() { System.out.println("doSome begin"); try { Thread.sleep(1000 * 10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("doSome over"); } public void doOther() { System.out.println("doOther begin"); System.out.println("doOther over"); } }
Exam2
package com.threadexam02; //Interview question: do you need to wait for doSome when the doOther method is executed //Yes, because the doOther method is decorated with synchronized, which modifies static variables and locks this public class Exam01 { public static void main(String[] args) throws InterruptedException { MyClass mc = new MyClass(); Thread t1 = new MyThread(mc); Thread t2 = new MyThread(mc); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000);//The function of this sleep is to ensure that the t1 thread executes first. t2.start(); } } class MyThread extends Thread { private MyClass mc; public MyThread(MyClass mc) { this.mc = mc; } @Override public void run() { if(Thread.currentThread().getName() == "t1"){ mc.doSome(); }else { mc.doOther(); } } } class MyClass { public synchronized void doSome() { System.out.println("doSome begin"); try { Thread.sleep(1000 * 10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("doSome over"); } public synchronized void doOther() { System.out.println("doOther begin"); System.out.println("doOther over"); } }
Exam3
package com.threadexam03; //Interview question: do you need to wait for doSome when the doOther method is executed //No, because two MCS, two this public class Exam01 { public static void main(String[] args) throws InterruptedException { MyClass mc1 = new MyClass(); MyClass mc2 = new MyClass(); Thread t1 = new MyThread(mc1); Thread t2 = new MyThread(mc2); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000);//The function of this sleep is to ensure that the t1 thread executes first. t2.start(); } } class MyThread extends Thread { private MyClass mc; public MyThread(MyClass mc) { this.mc = mc; } @Override public void run() { if(Thread.currentThread().getName() == "t1"){ mc.doSome(); }else { mc.doOther(); } } } class MyClass { public synchronized void doSome() { System.out.println("doSome begin"); try { Thread.sleep(1000 * 10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("doSome over"); } public synchronized void doOther() { System.out.println("doOther begin"); System.out.println("doOther over"); } }
Exam4
package com.threadexam04; //Interview question: do you need to wait for doSome when the doOther method is executed //Yes, because static methods are class locks. No matter how many objects are created, there is only one class lock| public class Exam01 { public static void main(String[] args) throws InterruptedException { MyClass mc1 = new MyClass(); MyClass mc2 = new MyClass(); Thread t1 = new MyThread(mc1); Thread t2 = new MyThread(mc2); t1.setName("t1"); t2.setName("t2"); t1.start(); Thread.sleep(1000);//The function of this sleep is to ensure that the t1 thread executes first. t2.start(); } } class MyThread extends Thread { private MyClass mc; public MyThread(MyClass mc) { this.mc = mc; } @Override public void run() { if(Thread.currentThread().getName() == "t1"){ mc.doSome(); }else { mc.doOther(); } } } class MyClass { //synchronized appears on static methods to find class locks. public synchronized static void doSome() { System.out.println("doSome begin"); try { Thread.sleep(1000 * 10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("doSome over"); } public synchronized static void doOther() { System.out.println("doOther begin"); System.out.println("doOther over"); } }
8 deadlock
How did the deadlock happen?
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-qhapiqle-1635520552500)( https://i.loli.net/2021/10/26/fuMOpy5VsnqtAr4.png )]
synchronized is best not to be nested in development.
Deadlock code
package com.deadlock; /*Deadlock code should be able to write. The general interviewer requires you to be able to write. Only those who can write will pay attention to this in future development. Because deadlocks are difficult to debug. */ public class DeadLock { public static void main(String[] args){ Object o1 = new Object(); Object o2 = new Object(); //t1,t2 share o1,o2 Thread t1 = new MyThread1(o1,o2); Thread t2 = new MyThread2(o1,o2); t1.start(); t2.start(); } } class MyThread1 extends Thread { Object o1; Object o2; public MyThread1(Object o1, Object o2) { this.o1 = o1; this.o2 = o2; } public void run() { synchronized (o1) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o2) { } } } } class MyThread2 extends Thread { Object o1; Object o2; public MyThread2 (Object o1, Object o2) { this.o1 = o1; this.o2 = o2; } public void run(){ synchronized (o2) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o1) { } } } }
9 how to solve thread safety problems in development
Thread synchronization synchronized is not preferred
-
synchronized will reduce the execution efficiency of the program and the user experience is not good.
-
The user throughput of the system is reduced. The user experience is poor. Choose thread synchronization mechanism when you have to.
Thoughts on solving thread safety problems in development
-
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
In this way, the memory of instance variables is not shared. (one thread corresponds to one object, and 100 threads correspond to 100 objects. 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.
10 daemon thread
Threads in java language are divided into two categories
- One is user thread
- One is daemon thread (background thread)
The representative one is garbage collection thread (daemon thread).
Characteristics of daemon thread
Generally, the daemon thread is an endless loop. As long as all user threads end, the daemon thread ends automatically.
Note: the main method of the main thread is a user thread.
Where are daemon threads used?
The system data is automatically backed up at 00:00 every day. This requires a timer, and we can set the timer as a daemon thread.
Always watch there and back up every 00:00. If all user threads end, the daemon thread will exit automatically. There is no need to back up the data.
Daemon thread
package com.thread; public class ThreadTest14 { public static void main(String[] args) { BakDataThread b = new BakDataThread(); b.setName("BackupData"); //Set the thread as a daemon before starting b.setDaemon(true); b.start(); //Main thread: the main thread is the user thread for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+"--->"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class BakDataThread extends Thread{ public void run(){ int i = 0; while (true){ System.out.println(Thread.currentThread().getName()+"---->"+(++i)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
12 timer
Function of timer
Execute specific programs at specific intervals.
General ledger operation of bank account shall be carried out every week. Backup data every day.
In actual development, it is very common to execute a specific program every other time. In fact, there are many ways to implement it in java:
- You can use the sleep method to sleep, set the sleep time, wake up before this time point and perform tasks. This method is the most primitive timer. (compare low)
- A timer, java.util.Timer, has been written in the Java class library, which can be used directly. However, this method is rarely used in current development, because many advanced frameworks support timed tasks.
- 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.
timer
package com.thread; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; //Use a timer to specify a scheduled task. public class TimerTest { public static void main(String[] args) throws ParseException { Timer timer = new Timer(); //Timer timer = new Timer(true); daemon mode //Specify scheduled tasks //Timer.schedule (scheduled task, first execution time, and how often to execute it); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Date firstdate = sdf.parse("2021-10-29 18:30:00"); timer.schedule(new LogTimerTask(),firstdate,1000*10); //Anonymous inner classes can be used here } } //Write scheduled task class //Suppose this is a scheduled task for logging class LogTimerTask extends TimerTask { @Override public void run() { //Just write the tasks you need to perform. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String strTime = sdf.format(new Date()); System.out.println(strTime+"Completed a data backup"); } }
13 FutureTask
The third way to implement threads. Implement the callable interface. (new feature of JDK8.)
Advantages: you can get the execution result of the thread.
Disadvantages: the efficiency is relatively low. When obtaining the execution results of seven threads, the current thread is blocked and the efficiency is low.
package com.thread; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class ThreadTest15 { public static void main(String[] args) throws ExecutionException, InterruptedException { //Step 1: create a "future task class" object. FutureTask futureTask = new FutureTask(new Callable() { @Override public Object call() throws Exception { //The call method is equivalent to the run method, but it has a return value System.out.println("call methid begin"); Thread.sleep(1000*3); System.out.println("call method end"); int a = 100; int b = 200; return a+b; //Automatic packing } }); //Create thread object Thread t = new Thread(futureTask); t.start(); //Here is the main method, which is in the main thread. //In the main thread, how to get the return result of t thread? //The execution of get() method will cause "current thread blocking" Object obj = futureTask.get(); System.out.println("Thread execution result:"+obj); //main method the program here must wait for the end of the get() method to execute //The get() method may take a long time, because the get() method is to get the execution result of another thread //Another thread takes time to execute. System.out.println("hello world"); } }
14 about the wait and notify methods in the object class.
wait and notify in object class
-
First, the wait and notify methods are not methods of Thread objects, but methods of any java object in java, because these two methods are built-in in the object class.
The wait method and notify method are not called through the thread object. It is not like this: t.wait(), nor is it like this: t.notify(). No. -
Second: what is the function of the wait() method?
Object o = new Object ( ) ; o.wait();
express:
Let the thread active on the o object enter the waiting state and wait indefinitely until it is awakened.
o. The call of the wait(); method will make the current thread (the thread active on the O object) "enter the waiting state". -
Third: what is the function of the notify() method?
[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-presvg7b-1635520552501)( https://i.loli.net/2021/10/29/KCj2nsDW5kelPpb.png )]
Object o = new Object ( ) ; o.notify();
express:
Wakes up the thread waiting on the object.
One more
notifyAll();
This method wakes up all the waiting threads on the object.
Producer and consumer model
[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-tucvhqhu-1635520552502)( https://i.loli.net/2021/10/29/TQCsvnN7zy6j5BY.png )]
-
Using the wait method and notify method to implement the "producer and consumer model"
-
What is the "producer and consumer model"?
The production thread is responsible for production and the consumption thread is responsible for consumption.
Production threads and consumption threads should be balanced.
This is a special business requirement. In this special case, you need to use the wait method and notify method.
-
The wait and notify methods are not thread object methods, but common java object methods.
-
The wait method and notify method are based on thread synchronization. Because multiple threads operate a warehouse at the same time, there is a thread safety problem.
-
The function of the wait method: o.wait() causes the active thread t on the. Object to enter the waiting state, and releases the lock of the. Object held by the seven threads before.
-
Function of notify method: o.notify() wakes up the thread waiting on the O object. It is only a notification and will not release the lock previously held on the object.
Simulate such a requirement:
We use the List set in the warehouse.
It is assumed that only 1 element can be stored in the List collection.
One element indicates that the warehouse is full.
If the number of elements in the List collection is, the warehouse is empty.
Ensure that at most 1 element is always stored in the List collection.
This effect must be achieved: one for production and one for consumption.
package com.thread; import java.util.ArrayList; import java.util.List; public class ThreadTest16 { public static void main(String[] args) { //Create pants object List list = new ArrayList(); //Create two thread objects //Producer thread Thread t1 = new Thread(new Producer(list)); //Consumer thread Thread t2 = new Thread(new Consumer(list)); t1.setName("Producer thread"); t2.setName("Consumer thread"); t1.start(); t2.start(); } } //Production thread class Producer implements Runnable{ //Warehouse private List list; public Producer(List list) { this.list = list; } @Override public void run() { //Always produce while (true){ //Lock the warehouse object List. synchronized (list){ if(list.size() > 0){ try { //The current thread enters the waiting state and releases the lock of the List collection previously occupied by the Producer. list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //The program can be executed here, indicating that the warehouse is empty and can be produced Object obj = new Object(); list.add(obj); System.out.println(Thread.currentThread().getName()+"--->"+obj); // Awaken consumers to consume list.notifyAll(); } } } } //Consumption thread class Consumer implements Runnable{ private List list; public Consumer(List list) { this.list = list; } @Override public void run() { while (true){ synchronized (list){ if(list.size() == 0){ //The warehouse is empty. //The consumer thread waits and releases the lock of the List collection try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //The program can be executed here, indicating that there is data in the warehouse for consumption. Object obj = list.remove(0); System.out.println(Thread.currentThread().getName()+"--->"+obj); //Awaken producers to produce. list.notifyAll(); } } } }
task
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-3phj6bbx-1635520552503)( https://i.loli.net/2021/10/29/UAuTeP6Bw4JY1ym.png )]