1. Thread introduction
Multitasking: it seems that multiple tasks are doing at the same time. In fact, only one thing is done at the same time. Switching will soon lead to more things at the same time.
Multithreading: multiple lines do multiple things at the same time, multiple execution paths, and the main thread and sub thread execute alternately in parallel.
Program: a program is an ordered collection of instructions and data. It has no running meaning and is a static concept.
Process: it is a process of executing a program. It is a dynamic concept. It is the unit of system resource allocation.
Thread: a process can contain multiple threads. Thread is the unit of CPU scheduling and execution.
[note]: many multithreads are simulated. Real multithreading refers to having multiple CPUs, i.e. multiple cores, such as servers. If it is a simulated multithreading, that is, in the case of one CPU, the CPU can only execute one code at the same time point. Because the switching is fast, there is the illusion of simultaneous execution.
2. Thread creation*
Three creation methods: Thread (class) (key) Runnable (Interface) (key) Callable (Interface) (understand)
2.1 inherit Thread class
package study.javaSaenior.thread.demo01; /** * Thread creation method 1: inherit the thread class, rewrite the run() method, and call start to start the thread * Summary: when the thread is started, the computer does not necessarily execute it immediately, but it is scheduled by the CPU. * @author zhengxu * @create 2021-05-23 10:07 */ //1. Inherit Thread class public class TestThread1 extends Thread{ //2. Rewrite the run() method @Override public void run() { //run method body for (int i = 0; i < 20; i++) { System.out.println("I'm looking at the code-------"+i); } } public static void main(String[] args) { //main thread //3. Create a thread object TestThread1 testThread1=new TestThread1(); //4. Call the start() method to start the thread testThread1.start(); for (int i = 0; i < 20; i++) { System.out.println("I'm learning multithreading--------"+i); } } } Operation results: I'm learning multithreading--------0 I'm looking at the code-------0 I'm looking at the code-------1 I'm learning multithreading--------1 I'm learning multithreading--------2 I'm learning multithreading--------3 I'm learning multithreading--------4 I'm looking at the code-------2
Case: online map download
import java.net.URL; /** * Practice Thread to realize multi-threaded synchronous downloading of pictures * @author zhengxu * @create 2021-05-23 10:22 */ public class TestThread2 extends Thread{ private String url;//Network picture address private String name;//Saved file name public TestThread2(String url,String name){ this.url=url; this.name=name; } //Download the execution body of the picture @Override public void run() { WebDownloader webDownloader=new WebDownloader(); webDownloader.downloader(url,name); System.out.println("Downloaded the file named:"+name); } public static void main(String[] args) { TestThread2 t1=new TestThread2("https://pics5.baidu.com/feed/f636afc379310a55ebfb2465fee3c9a1802610f6.jpeg?token=a360db8d557254f145f763044be748fa","1.jpg"); TestThread2 t2=new TestThread2("https://pics1.baidu.com/feed/03087bf40ad162d986bd5b4f0a5b23e48b13cd9a.jpeg?token=a97dba301dd813678ae8d990093ae4cf","2.jpg"); TestThread2 t3=new TestThread2("https://pics6.baidu.com/feed/38dbb6fd5266d0164e71448c8aaf5e0f34fa35b2.jpeg?token=fb0a64bbb1beae0a91826614da4ab8e0","3.jpg"); t1.start(); t2.start(); t3.start(); } } class WebDownloader{ //Download method public void downloader(String url,String name){ try { FileUtils.copyURLToFile(new URL(url),new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("IO Abnormal, downloader There is a problem with the method"); } } }
2.2 implementation of Runnable interface
package study.javaSaenior.thread.demo01; /** * Thread creation mode 2: implement the Runnable interface and rewrite the run() method. The execution thread needs to throw into the runnnable interface implementation class and call the start() method * @author zhengxu * @create 2021-05-24 9:06 */ public class TestThread3 implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("I'm looking at the code---"+i); } } public static void main(String[] args) { //Create the implementation class object of runnable interface TestThread3 testThread3=new TestThread3(); //Create a thread object and start the thread agent through the thread object // Thread thread = new Thread(testThread3); // thread.start(); new Thread(testThread3).start(); for (int i = 0; i < 100; i++) { System.out.println("I'm learning multithreading--"+i); } } }
[summary]
-
Inherit Thread class
- The subclass inherits the Thread class and has the ability of multithreading
- Start thread: subclass object start();
- Not recommended: avoid the limitation of OOP single inheritance
-
Implement Runnable interface
- The implementation interface Runnable has multithreading capability
- Start Thread: pass in the target object + Thread object start();
- Recommended: it avoids the limitation of single inheritance, is flexible and convenient, and is convenient for the same object to be used by multiple threads.
2.3 implement Callable interface (just understand)
package study.javaSaenior.thread.demo02; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.concurrent.*; /** * Create multithreading method 3: implement Callable interface (just understand) * 1.To implement the Callable interface, the return value type is required * 2.When overriding the call method, you need to throw an exception * 3.Create target object * 4.Create execution service: executorservice ser = executors newFixedThreadPool(1); * 5.Submit execution: future < Boolean > result = Ser submit(t1); * 6.Get result: Boolean R1 = result1 get() * 7.Shut down the service: Ser shutdownNow() * * Callable Benefits: * 1.You can define the return value * 2.Exceptions can be thrown * @author zhengxu * @create 2021-05-24 10:01 */ public class TestCallable implements Callable { private String url;//Network picture address private String name;//Saved file name public TestCallable(String url,String name){ this.url=url; this.name=name; } //Download the execution body of the picture @Override public Boolean call() { WebDownloader webDownloader=new WebDownloader(); webDownloader.downloader(url,name); System.out.println("Downloaded the file named:"+name); return true; } public static void main(String[] args) throws ExecutionException, InterruptedException { TestCallable t1=new TestCallable("https://pics5.baidu.com/feed/f636afc379310a55ebfb2465fee3c9a1802610f6.jpeg?token=a360db8d557254f145f763044be748fa","1.jpg"); TestCallable t2=new TestCallable("https://pics1.baidu.com/feed/03087bf40ad162d986bd5b4f0a5b23e48b13cd9a.jpeg?token=a97dba301dd813678ae8d990093ae4cf","2.jpg"); TestCallable t3=new TestCallable("https://pics6.baidu.com/feed/38dbb6fd5266d0164e71448c8aaf5e0f34fa35b2.jpeg?token=fb0a64bbb1beae0a91826614da4ab8e0","3.jpg"); //Create execution service: ExecutorService ser= Executors.newFixedThreadPool(3); //Submit for execution: Future<Boolean> r1=ser.submit(t1); Future<Boolean> r2=ser.submit(t2); Future<Boolean> r3=ser.submit(t3); //Get results: boolean rs1=r1.get(); boolean rs2=r2.get(); boolean rs3=r3.get(); //Shut down service: ser.shutdownNow(); } } class WebDownloader{ //Download method public void downloader(String url,String name){ try { FileUtils.copyURLToFile(new URL(url),new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("IO Abnormal, downloader There is a problem with the method"); } } }
3. Learn about concurrency
package study.javaSaenior.thread.demo01; /** * Multiple threads operate on an object at the same time * Example: train ticket sale * * Problems found: when multiple threads operate on the same resource, the thread is unsafe and the data is disordered. * @author zhengxu * @create 2021-05-24 9:22 */ public class TestThread4 implements Runnable { private int ticket=10; @Override public void run() { while(true){ if(ticket<=0){ break; } try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->Got the second"+ticket--+"Tickets"); } } public static void main(String[] args) { TestThread4 testThread4=new TestThread4(); new Thread(testThread4,"Xiao Ming").start(); new Thread(testThread4,"teacher").start(); new Thread(testThread4,"cattle").start(); } }
Case: Tortoise and rabbit Race race Race race
package study.javaSaenior.thread.demo01; /** * Case: Tortoise rabbit race * 1.First take a distance from the track, and then get closer and closer to the finish line * 2.Judge whether the game is over * 3.Print out the winner * 4.The tortoise and rabbit race began * 5.In the story, the tortoise wins and the rabbit needs to sleep, so let's simulate the rabbit to sleep * 6.Finally, the tortoise won the game * @author zhengxu * @create 2021-05-24 9:40 */ public class Race implements Runnable{ //winner private static String winner; @Override public void run() { for (int i = 0; i <= 100; i++) { //Simulated rabbit sleep if(Thread.currentThread().getName()=="rabbit"){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } //Judge whether the game is over boolean flag=gameOver(i); //Stop the program if the game is over if(flag==true){ break; } System.out.println(Thread.currentThread().getName()+"Run away"+i+"step"); } } //Judge whether the game is over private boolean gameOver(int step){ //Determine whether there is already a winner if(winner!=null){//There are already winners return true; }else{ if(step>=100){ winner=Thread.currentThread().getName(); System.out.println("Winner is"+winner); return true; } } return false; } public static void main(String[] args) { Race race=new Race(); new Thread(race,"rabbit").start(); new Thread(race,"tortoise").start(); } }
4. Static proxy mode
package study.javaSaenior.thread.demo02; /** * Summary of static proxy mode: * 1.Both real objects and proxy objects should implement the same interface * 2.The proxy object should represent the real role * Benefits: * 1.Proxy objects can do many things that real objects cannot do * 2.Real objects can focus on doing their own things. * @author zhengxu * @create 2021-05-24 10:32 */ public class StaticProxy { public static void main(String[] args) { You you=new You();//Are you getting married //Analogy two implementation principles, very similar //Thread is equivalent to a proxy object, and the runnable interface in parentheses is equivalent to a real object new Thread( ()-> System.out.println("I love you!")).start(); new WeddingCompany(you).HappyMarry(); } } interface Marry{ //Four great happenings in the world void HappyMarry(); } //Real role class You implements Marry{ @Override public void HappyMarry() { System.out.println("I'm getting married. I'm so happy!"); } } //Acting role to help you get married class WeddingCompany implements Marry{ //Who to represent -- > real target role private Marry target; public WeddingCompany(Marry target) { this.target = target; } @Override public void HappyMarry() { before(); this.target.HappyMarry();//This is the real object after(); } private void before() { System.out.println("Before marriage, set up the scene"); } private void after() { System.out.println("After marriage, the final payment"); } }
5.Lambda expression
Why use lambda expressions
- Avoid too many anonymous inner class definitions
- It can make your code look neat
- Removed a pile of meaningless code, leaving only the core logic
Understanding the Functional Interface is the key to learning java 8 lambda expressions
Definition of functional interface:
- Any interface that contains only one abstract method is a functional interface.
public interface Runnable{ public abstract void run(); }
- For functional interfaces, we can create objects of the interface through lambda expressions.
package study.javaSaenior.thread.demo03; /** * Deduce the evolution of lambda expression * @author zhengxu * @create 2021-05-24 19:48 */ public class TestLambda01 { //3. Static internal class static class Like2 implements ILike{ @Override public void lambda() { System.out.println("I like lambda2"); } } public static void main(String[] args) { ILike like=new Like(); like.lambda(); like=new Like2(); like.lambda(); //4. Local internal class class Like3 implements ILike{ @Override public void lambda() { System.out.println("I like lambda3"); } } like=new Like3(); like.lambda(); //5. Anonymous inner class: if there is no class name, you must use the interface or parent class like=new ILike() { @Override public void lambda() { System.out.println("I like lambda4"); } }; like.lambda(); //6. Simplify with lambda like=()->{ System.out.println("I like lambda5"); }; like.lambda(); } } //1. Define a functional interface interface ILike{ void lambda(); } //2. Implementation class class Like implements ILike{ @Override public void lambda() { System.out.println("I like lambda1"); } }
package study.javaSaenior.thread.demo03; /** * lambda expression with parameters * Summary: * 1.lambda The expression can only be simplified into one line if there is only one line of code. If there are multiple lines, wrap {} with code blocks * 2.The premise is that the interface is a functional interface (there is only one interface in the interface) * 3.The parameter type can also be removed from multiple parameters. If you want to remove them, you must add parentheses (a, b) - > code block * @author zhengxu * @create 2021-05-24 20:07 */ public class TestLambda02 { public static void main(String[] args) { ILove love=new Love(); love.love(1); //lambda simplification 1 love=(int a)->{System.out.println("I love you"+a);}; //lambda simplification 2: parameter types love=(a)->{System.out.println("I love you"+a);}; //lambda 3: simplify parentheses love=a->{System.out.println("I love you"+a);}; //lambda 4: simplify curly braces love=a-> System.out.println("I love you"+a); love.love(2); } } interface ILove{ void love(int a); } class Love implements ILove{ @Override public void love(int a) { System.out.println("I love you"+a); } }
Completely simplified code
package study.javaSaenior.thread.demo03; public class TestLambda02 { public static void main(String[] args) { ILove love=a-> System.out.println("I love you"+a); love.love(2); } } interface ILove{ void love(int a); }
6. Thread status
[the external chain image transfer fails. The source station may have anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-7zrtlyx1-1622090764969) (C: \ users \ Zhengxu \ appdata \ roaming \ typora user images \ image-20210521165815921. PNG)]
6.1 common methods of multithreading
-
**void start() 😗* Start the thread and execute the run() method of the object
-
**run() 😗* The operation that a thread performs when it is scheduled
-
**String getName() 😗* Returns the name of the thread
-
**viod setName(String name) 😗* Set the thread name
-
**static Thread currentThread() 😗* Returns the current thread. When this is in a subclass, it is usually used for the main thread and Runnable implementation class
-
**static void yield() 😗* Thread concession. Pause the currently running thread and give the opportunity to the thread with the same or higher priority
-
**join() 😗* When the join () method of other threads is invoked in a program execution stream, the calling thread will be blocked until the join thread added by the join () method is executed.
-
static void sleep(long millis): (specified time: milliseconds). Make the current active thread give up control over the CPU within the specified time period, and other threads have the opportunity to be executed. When the time comes, queue up again.
Throw an InterruptionException exception.
-
**stop() 😗* Force the end of thread life cycle. It is not recommended.
-
**boolean isAlive: * * returns boolean to judge whether the thread is still alive.
-
**suspend() 😗* Suspended, not recommended.
-
**resume() 😗* End pending status, not recommended.
-
**notify()/notifyAll() 😗* awaken
6.2 stopping threads
- The stop(), destroy() method provided by JDK is not recommended. [abandoned]
- It is recommended to let the thread stop by itself
- It is recommended to use a flag bit to terminate the variable. When flag=false, the thread is terminated.
package study.javaSaenior.thread.demo03; /** * Test stop * 1.It is recommended that threads stop normally - > utilization times, and do not loop * 2.It is recommended to use flag bit - > set a flag bit * 3.Do not use outdated methods such as stop or destroy, or methods that are not recommended by JDK * @author zhengxu * @create 2021-05-24 20:54 */ public class TestStop implements Runnable{ //1. Define the ID used by the thread body in the thread private Boolean flag=true; @Override public void run(){ int i=0; //2. The thread body uses this ID while(flag){ System.out.println("run....Thread"+i++); } } //3. Provide external method change identification public void stop(){ this.flag=false; } public static void main(String[] args) { TestStop testStop=new TestStop(); new Thread(testStop).start(); for (int i = 0; i < 1000; i++) { System.out.println("main"+i); if(i==900){ //Call the stop method to switch the flag bit and stop the thread testStop.stop(); System.out.println("The thread stopped"); } } } }
6.3 thread hibernation
package study.javaSaenior.thread.demo03; import java.text.SimpleDateFormat; import java.util.Date; /** * Analog countdown * 1.sleep(Time) specifies the number of milliseconds the current thread is blocking * 2.sleep There is an exception InterruptedException * 3.sleep When the time reaches, the thread enters the ready state * 4.sleep It can simulate network delay, countdown, etc. * 5.Every object has a lock, and sleep will not release the lock. * @author zhengxu * @create 2021-05-24 21:39 */ public class TestSleep02 { public static void main(String[] args) { // try { // tenDown(); // } catch (InterruptedException e) { // e.printStackTrace(); // } //Print current system time Date startTime=new Date(System.currentTimeMillis()); while(true){ try { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime)); startTime=new Date(System.currentTimeMillis());//Update current time } catch (InterruptedException e) { e.printStackTrace(); } } } //Analog countdown public static void tenDown() throws InterruptedException { int num=10; while(true){ Thread.sleep(1000); System.out.println(num--); if(num<=0){ break; } } } }
6.4 comity
- Pause the current thread without blocking it
- Change the thread from running state to ready state
- Let the CPU reschedule, comity is not necessarily successful! Look at CPU mood
package study.javaSaenior.thread.demo03; /** * @author zhengxu * @create 2021-05-24 22:17 */ public class TestYield { public static void main(String[] args) { MyYield yield=new MyYield(); new Thread(yield,"a").start(); new Thread(yield,"b").start(); } } class MyYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"The thread starts executing"); Thread.yield();//Thread comity System.out.println(Thread.currentThread().getName()+"Thread stop execution"); } }
6.5 thread enforcement
- join merge threads. After this thread completes execution, execute other threads. Other threads are blocked.
- It can be imagined as queue jumping and VIP channel.
package study.javaSaenior.thread.demo03; /** * Test join method: imagine jumping in line * @author zhengxu * @create 2021-05-24 22:23 */ public class TestJoin implements Runnable { @Override public void run() { for (int i = 0; i <=1000; i++) { System.out.println("thread VIP coming"+i); } } public static void main(String[] args) throws InterruptedException { //Start our thread TestJoin testJoin=new TestJoin(); Thread thread=new Thread(testJoin); thread.start(); //Main thread for (int i = 0; i < 1000; i++) { if(i==200){ thread.join();//Jump in line } System.out.println("main"+i); } } }
6.6 thread state observation
-
Thread.State
Thread status. A thread can be in one of the following states
-
NEW
Threads that have not been started are in this state
-
RUNNABLE
The thread executing in the Java virtual machine is in this state
-
BLOCKED
Threads that are blocked waiting for a monitor lock are in this state
-
WAITING
A thread that is waiting for another thread to perform a specific action is in this state
-
TIMED_WAITING
The thread that is waiting for another thread to perform the action for the specified waiting time is in this state
-
TERMINATED
The exited thread is in this state
-
A thread can be in a state at a given point in time. These states are virtual machine states that do not reflect any operating system thread state.
package study.javaSaenior.thread.demo03; /** * Observe the status of the test thread * @author zhengxu * @create 2021-05-24 23:02 */ public class TestState { public static void main(String[] args) throws InterruptedException { Thread thread=new Thread(()->{ for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("///"); }); //Observation state Thread.State state=thread.getState(); System.out.println(state);//NEW //Observe after startup thread.start(); state=thread.getState(); System.out.println(state);//RUNABLE while (state!=Thread.State.TERMINATED){//The thread does not terminate as long as it is in the output state Thread.sleep(100); state=thread.getState();//Update thread status System.out.println(state); } } }
7. Thread priority
- Java provides a thread scheduler to monitor all threads that enter the ready state after startup. The thread scheduler determines which thread should be scheduled to execute according to priority.
- The priority of threads is expressed in numbers, ranging from 1 to 10
- Thread.MIN_PRIORITY=1;
- Thread.MAX_PRIORITY=10;
- Thread.NORM_PRIORITY=5;
- Change or obtain priorities in the following ways
- getPriority() setPriority(int xxx)
package study.javaSenior.thread.demo03; /** * Test thread priority * Conclusion: low priority only means that the probability of obtaining scheduling is low, not that it will not be called if the priority is low, which depends on the scheduling of CPU. * @author zhengxu * @create 2021-05-26 8:37 */ public class TestPriority { public static void main(String[] args) { //The main thread has the default priority System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority()); MyPriority myPriority=new MyPriority(); Thread t1=new Thread(myPriority); Thread t2=new Thread(myPriority); Thread t3=new Thread(myPriority); //Set priority before starting t1.setPriority(1); t2.setPriority(3); t3.setPriority(Thread.MAX_PRIORITY);//10 t1.start(); t2.start(); t3.start(); } } class MyPriority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority()); } }
8. Daemon thread
Daemon thread
- Threads are divided into user threads and daemon threads
- The virtual machine must ensure that the user thread has completed execution
- The virtual machine does not have to wait for the daemon thread to finish executing
- Such as: recording operation logs in the background, monitoring memory, garbage collection, etc
package study.javaSenior.thread.demo03; /** * Test daemon thread: God guards you * @author zhengxu * @create 2021-05-26 8:51 */ public class TestDaemon { public static void main(String[] args) { God god=new God(); You you=new You(); Thread thread=new Thread(god); thread.setDaemon(true);//The default is false, which means that it is a user thread. Normal threads are user threads thread.start();//God Guardian thread qid new Thread(you).start();//Your user thread starts } } //lord class God implements Runnable{ @Override public void run() { while (true){ System.out.println("God bless you"); } } } //you class You implements Runnable{ @Override public void run() { for (int i = 0; i < 36500; i++) { System.out.println("Have you been happy all your life"); } System.out.println("======goodbye! world!======="); } }
9. Thread synchronization*
Multiple threads operate on the same resource
Concurrency: the same object is operated by multiple threads at the same time
Thread synchronization is actually a waiting mechanism. Multiple threads that need to access this object at the same time enter the waiting pool of this object to form a queue, wait for the previous thread to use it, and then use it for the next thread. Solve the problem of thread insecurity
Forming conditions: queue + lock
- Because multiple threads of the same process share the same storage space, it brings convenience and access conflict. In order to ensure the correctness of data being accessed in the method, the lock mechanism is added during access. When one thread obtains the exclusive lock of the object and monopolizes resources, other threads must wait and release the lock after use. The following problems exist:
- A thread holding a lock will cause other threads that need the lock to be suspended
- In multi-threaded competition, locking and releasing locks will lead to more context switching and scheduling delays, resulting in performance problems
- If a high priority thread waits for a low priority thread to release the lock, it will lead to priority inversion and performance problems
9.1 three unsafe cases - buying tickets
package study.javaSenior.thread.syn; /** * Three unsafe cases: unsafe ticket buying * @author zhengxu * @create 2021-05-26 9:18 */ public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket station=new BuyTicket(); new Thread(station,"Forced me").start(); new Thread(station,"Damn you").start(); new Thread(station,"Damn scalpers").start(); } } class BuyTicket implements Runnable{ //ticket private int ticketNums = 10; boolean flag=true;//External stop mode @Override public void run() { //Buy a ticket while (flag){ try { buy(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void buy() throws InterruptedException { //Judge whether there are tickets if(ticketNums<=0){ flag=false; return; } //Analog delay Thread.sleep(100); //Buy a ticket System.out.println(Thread.currentThread().getName()+"Bought the second"+ticketNums--+"Tickets"); } } //There will be - 1 votes.
9.2 three unsafe cases - Banks
package study.javaSenior.thread.syn; /** * Unsafe withdrawal: two people withdraw money * @author zhengxu * @create 2021-05-26 10:06 */ public class UnsafeBank { public static void main(String[] args) { //account Account account=new Account(100,"Marriage fund"); Drawing you=new Drawing(account,50,"you"); Drawing girlFriend=new Drawing(account,100,"girl friend"); you.start(); girlFriend.start(); } } //account class Account{ int money;//balance String name;//Card name public Account(int money,String name){ this.money=money; this.name=name; } } //Bank: simulated withdrawal class Drawing extends Thread{ Account account;//account //How much did you withdraw int drawingMoney; //How much money do you have now int nowMoney; public Drawing(Account account,int drawingMoney,String name){ super(name); this.account=account; this.drawingMoney=drawingMoney; } @Override public void run() { //Judge whether there is money if(account.money-drawingMoney<0){ System.out.println(Thread.currentThread().getName()+"There's not enough money to withdraw"); return; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //Card balance = balance - the money you withdraw account.money=account.money-drawingMoney; //The money in your hand nowMoney=nowMoney+drawingMoney; System.out.println(account.name+"The balance is:"+account.money); //Because of inheritance: this getName()=Thread. currentThread(). getName() System.out.println(this.getName()+"Money in hand:"+nowMoney); } } //Operation results: //Marriage fund balance: 50 //Marriage fund balance: 50 //Money in your hand: 50 //Money in girlfriend's hand: 100
9.3 three unsafe cases - Collection
package study.javaSenior.thread.syn; import java.util.ArrayList; import java.util.List; /** * Thread unsafe collection * Thread Runtime: when two threads run at the same time, the array is generated to the same location and covered. * @author zhengxu * @create 2021-05-26 17:06 */ public class UnsafeList { public static void main(String[] args) { List<String> list=new ArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } } //Operation results: //9998
9.4 synchronization method
public synchronized void method(int args){}
- The synchronized method controls the access to "objects". Each object corresponds to a lock. Each synchronized method must obtain the lock of the object calling the method before it can be executed, otherwise the thread will be blocked. Once the method is executed, it will monopolize the lock and release the lock until the method returns. Only the blocked thread can obtain the lock and continue to execute.
- **Defect: * * declaring a large method synchronized will affect efficiency. Only the contents that need to be modified in the method need to be locked. Too many locks will waste resources.
The duplicate ticket problem in the ticket selling example is a typical thread safety problem.
/** * Example 2: create three windows with a total of 100 votes, using the way to implement the Runnale interface * * 1.Problem: there are problems of duplicate tickets and wrong tickets in the process of buying tickets - > there is a thread safety problem * 2.Cause of the problem: when a thread operates the thread and the operation has not been completed, other threads participate and operate the ticket. * 3.Solution: when a thread is operating the ticket, other threads cannot participate. Only when the current thread completes the operation can other threads participate. * Even if the current thread is blocked, it cannot be changed. * 4.Java In, we solve the problem of thread safety through synchronization mechanism. * * Method 1: synchronize code blocks * synchronized(Synchronization monitor){ * //Code to be synchronized * } * Description: 1 The code that operates the shared data is the code that needs to be synchronized. -- > Cannot contain more or less code * 2.Shared data: variables operated by multiple threads. For example, a ticket is sharing data. * 3.Synchronous monitor, commonly known as lock. The object of any class can act as a lock. * Requirement: multiple threads must share the same lock!!!!!! The monitor can be changed into static by inheriting Thread * Add: in the way of implementing Runnable interface to create multithreading, you can consider using this as the synchronization monitor. * Using synchronous code block to solve the Thread safety problem of inheriting Thread class, you can turn obj into static to prevent the monitor from being not unique. * * Method 2: synchronization method * If the code that operates on shared data is completely declared in a method, we might as well declare this method synchronous. * 1.The synchronization method still involves the synchronization monitor, as long as we don't need to explicitly declare it. * 2.The synchronization monitor of non static synchronization method is: this * 3.The synchronization monitor of the static method is: the current class itself, XX class * * 5.The way of synchronization solves the problem of thread safety. - > benefit * While operating the synchronization code, only one thread can participate and other threads wait. It is equivalent to a single threaded process with low efficiency shortcoming */
9.4.1 the synchronous code block method deals with the security problem of creating multithreads by Runnable interface
package study.javaSaenior.exercise; class Window1 implements Runnable{ private int ticket=100;//You don't need to use static, because only one Window1 is instantiated in main!!!! Object obj=new Object();//Here, three threads share a lock, and three locks are placed in run(). @Override public void run() { while (true) { //synchronized(this) { //synchronized(window1.class) { synchronized(obj) { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + ":Ticket number:" + ticket); ticket--; } else { break; } } } } } public class WindowTest01 { public static void main(String[] args) { Window1 w=new Window1(); Thread t1=new Thread(w); Thread t2=new Thread(w); Thread t3=new Thread(w); t1.setName("Window 1"); t2.setName("Window 2"); t3.setName("Window 3"); t1.start(); t2.start(); t3.start(); } }
9.4.2 the synchronous code block method deals with thread safety problems caused by inheriting the tree class
package study.javaSaenior.exercise; /** * Use synchronous code blocks to solve the Thread safety problem of inheriting Thread class * * @author zhengxu * @create 2021-05-22 12:13 */ class Window2 extends Thread{ private static int ticket=100; private static Object obj=new Object(); @Override public void run() { while(true){ synchronized (obj) {//There will still be errors, because each of the following three windows has a lock, which can change obj into static!!!!!!!!!!!!! if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + ":Ticket number:" + ticket); ticket--; } else { break; } } } } } public class WindowTest02 { public static void main(String[] args) { Window2 w1=new Window2(); Window2 w2=new Window2(); Window2 w3=new Window2(); w1.setName("Window 1"); w2.setName("Window 2"); w3.setName("Window 3"); w1.start(); w2.start(); w3.start(); } }
9.4.3 the synchronization method deals with the thread safety problem of realizing Runnable
package study.javaSaenior.exercise; //Extract the method and add the modifier synchronized class Window4 implements Runnable{ private int ticket=100; @Override public void run() { while (true) { show(); } } private synchronized void show(){ //Synchronization method: the default synchronization monitor is this if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":Ticket number:" + ticket); ticket--; } } } public class WindowTest04 { public static void main(String[] args) { Window4 w=new Window4(); Thread t1=new Thread(w); Thread t2=new Thread(w); Thread t3=new Thread(w); t1.setName("Window 1"); t2.setName("Window 2"); t3.setName("Window 3"); t1.start(); t2.start(); t3.start(); } }
9.4.4 the synchronization method handles the Thread safety problem of inheriting Thread class
package study.javaSaenior.exercise; //Using synchronous methods to deal with Thread safety problems in the way of inheriting Thread class class Window3 extends Thread{ private static int ticket=100; @Override public void run() { while(true){ show(); } } //private synchronized void show() {/ / the synchronization monitor is this, but three threads corresponding to one lock are established. Error private static synchronized void show(){//Add a static, and the synchronization monitor is windows 4 class!!!!!!! if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":Ticket number:" + ticket); ticket--; } } } public class WindowTest03 { public static void main(String[] args) { Window3 w1=new Window3(); Window3 w2=new Window3(); Window3 w3=new Window3(); w1.setName("Window 1"); w2.setName("Window 2"); w3.setName("Window 3"); w1.start(); w2.start(); w3.start(); } }
10. Thread deadlock
-
deadlock
Different threads occupy the synchronization resources needed by the other party and do not give up. They are waiting for the other party to give up the synchronization resources they need, forming a thread deadlock.
After a deadlock occurs, there will be no exception or prompt, but all threads are blocked and cannot continue
-
resolvent
Special algorithms and principles
Minimize the definition of synchronization resources
Try to avoid nested synchronization
package study.javaSaenior.thread; /** * Demonstrate thread deadlock * Thread 1 is waiting, holding s1 is waiting for s2, and thread 2 is holding s2 and waiting for s1. A deadlock occurs * @author zhengxu * @create 2021-05-22 20:55 */ public class ThreadTest02 { public static void main(String[] args) { StringBuffer s1=new StringBuffer(); StringBuffer s2=new StringBuffer(); new Thread(){ @Override public void run() { synchronized (s1){ s1.append("a"); s2.append("1"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (s2){ s1.append("b"); s2.append("2"); System.out.println(s1); System.out.println(s2); } } } }.start(); new Thread(new Runnable() { @Override public void run() { synchronized (s2){ s1.append("c"); s2.append("3"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (s1){ s1.append("d"); s2.append("4"); System.out.println(s1); System.out.println(s2); } } } }).start(); } }
11.Lock lock
- From jdk5 Since 0, Java has provided a more powerful thread synchronization mechanism -- realizing synchronization by explicitly defining synchronization Lock objects. Synchronous locks use Lock objects as.
- java.util.concurrent.locks.Lock interface is a tool that controls multiple threads to access shared resources. Lock provides exclusive access to shared resources. Only one thread can lock the lock object at a time. The lock object should be alive before the thread starts to access shared resources.
- ReentrantLock (reentrant Lock) class implements Lock. It has the same concurrency and memory semantics as synchronized. ReentrantLock is commonly used in thread safety control, which can explicitly add and release locks.
package study.javaSenior.thread.gaoji; import java.util.concurrent.locks.ReentrantLock; /** * Test Lock * @author zhengxu * @create 2021-05-27 8:33 */ public class TestLock { public static void main(String[] args) { TestLock2 testLock2=new TestLock2(); new Thread(testLock2).start(); new Thread(testLock2).start(); new Thread(testLock2).start(); } } class TestLock2 implements Runnable{ int ticketNumbers=10; //Define reentrant Lock private final ReentrantLock lock=new ReentrantLock(); @Override public void run() { while (true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } try { lock.lock();//Lock if (ticketNumbers > 0) { System.out.println(Thread.currentThread().getName()+":"+ticketNumbers--); }else{ break; } }finally { //Unlock lock.unlock(); } } } }
-
Lock is an explicit lock (manually open and close the lock, don't forget to close the lock). synchronized is an implicit lock, which is automatically released out of the scope.
-
Lock only has code block lock, and synchronized has code block lock and method lock.
-
Using Lock lock, the JVM will spend less time scheduling threads and perform better. And it has better scalability (providing more subclasses).
-
Use priority:
Lock > synchronization code block (has entered the method body and allocated corresponding resources) > synchronization method (outside the method body)
12. Thread communication
Producer consumer model
Application scenario: producer and consumer issues
- Suppose that only one product can be stored in the warehouse, the producer puts the produced products into the warehouse, and the consumer takes the products from the warehouse for consumption,
- If there is no product in the warehouse, the producer will put the product into the warehouse, otherwise stop production and wait until the product in the warehouse is taken away by the consumer.
- If there is a product in the warehouse, the consumer can take the product away for consumption, otherwise stop consumption and wait until the product is put into the warehouse again.
This is a thread synchronization problem. Producers and consumers share the same resource, and producers and consumers are interdependent and conditional on each other.
Java provides a way to solve the communication problem between threads
- **wait(): * * indicates that the thread waits until other threads notify it. Unlike sleep, which releases the lock.
- **wait(long time) 😗* Wait for the specified number of milliseconds
- **notify() 😗* Wake up a waiting thread
- **notifyAll: * * wake up all threads calling the wait() method on the same object, and the threads with higher priority are scheduled first.
[note]: all methods of Object class can only be used in synchronization methods or synchronization code blocks, otherwise an exception lllegalMonitorStateException will be thrown
12.1 solution 1: pipe pass method
The producer puts the produced data into the buffer, and the consumer takes out the data from the buffer.
package study.javaSenior.thread.gaoji; /** * Producer buffer solution * Producer, consumer, product, buffer * @author zhengxu * @create 2021-05-27 10:13 */ public class TestPC { public static void main(String[] args) { SynContainer container=new SynContainer(); new Producer(container).start(); new Consumer(container).start(); } } //producer class Producer extends Thread{ SynContainer container; public Producer(SynContainer container){ this.container=container; } //production @Override public void run() { for (int i = 1; i < 100; i++) { container.push(new Chicken(i)); System.out.println("Produced the second"+i+"Chicken"); } } } //consumer class Consumer extends Thread{ SynContainer container; public Consumer(SynContainer container) { this.container = container; } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("Consumed the second"+container.pop().id+"Chicken"); } } } //product class Chicken{ int id; //Product number public Chicken(int id) { this.id = id; } } //buffer class SynContainer{ //A container size is required Chicken[] chickens=new Chicken[10]; //Container counter int count=0; //Producers put in products public synchronized void push(Chicken chicken){ //If the container is full, it needs to wait for consumers to consume if(count==chickens.length-1){ //Inform consumers and producers to wait try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else { //If it is not full, throw it into the product count++; chickens[count]=chicken; } //Consumers can be informed of consumption this.notifyAll(); } //Consumer products public synchronized Chicken pop(){ //Judge whether it can be consumed if(count==0){ //Consumers wait for producers to produce try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //If you can consume Chicken chicken=chickens[count]; count--; //After eating, inform the producer to produce this.notifyAll(); return chicken; } }
12.2 solution 2: signal lamp method
package study.javaSenior.thread.gaoji; /** * Test producer consumer problem 2: signal lamp method, flag bit solution * @author zhengxu * @create 2021-05-27 11:26 */ public class TestPC2 { public static void main(String[] args) { Tv tv=new Tv(); new Player(tv).start(); new Watcher(tv).start(); } } //Producer - > actor class Player extends Thread{ Tv tv; public Player(Tv tv){ this.tv=tv; } @Override public void run() { for (int i = 0; i < 100; i++) { if(i%2==0){ this.tv.play("Happy camp broadcast"); }else{ this.tv.play("Jitter: tiktok: record the good life"); } } } } //Consumer - > audience class Watcher extends Thread{ Tv tv; public Watcher(Tv tv){ this.tv=tv; } @Override public void run() { for (int i = 0; i < 100; i++) { tv.watch(); } } } //Products - > Programs class Tv{ //The audience waited and the actors performed String voice;//A performance boolean flag=true;//true indicates the amount of visitors, and false indicates that they haven't come yet //perform public synchronized void play(String voice){ if(!flag){ try { this.wait();//The audience didn't come, waiting for the audience to come this.voice=voice; System.out.println("The actors performed:"+voice);//Wait for the end and start the performance } catch (InterruptedException e) { e.printStackTrace(); } } //The audience came and began to perform this.flag=!this.flag;//At the end of the performance, the audience left this.notifyAll();//Remind the audience to come again } //watch public synchronized void watch(){ if(flag){ try { wait();//Waiting to watch System.out.println("The audience watched:"+voice);//Wait for the end and start watching } catch (InterruptedException e) { e.printStackTrace(); } } //Inform the actors to perform this.flag=!this.flag; this.notifyAll(); } }
13. Thread pool
- Background: often creating, destroying and using very large resources, such as threads in concurrency, has 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. It can avoid frequent creation and destruction and realize reuse. Similar to public transport in life.
- Benefits:
- Improved response speed (reduced time to create new threads)
- Reduce resource consumption (reuse threads in the thread pool and do not need to be created every time)
- Easy thread management (...)
- corePoolSize: the size of the core pool
- maximumPoolSize: maximum number of threads
- keepAliveTime: the maximum time a thread can hold without a task before terminating.
package study.javaSenior.thread.gaoji; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Test thread pool * @author zhengxu * @create 2021-05-27 12:30 */ public class TestPool { public static void main(String[] args) { //1. Create service and thread pool //The newFixedThreadPool parameter is the thread pool size ExecutorService service=Executors.newFixedThreadPool(10); ThreadPoolExecutor service1=(ThreadPoolExecutor) service; //Set thread pool properties service1.setCorePoolSize(15); service1.setKeepAliveTime(100); //2. Execute the specified thread operation. You need to provide an object that implements the Runnable interface or the Callable interface implementation class service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread());//Applicable to Runnable interface service.submit(new MyThread());//For Callable interface //3. Close the connection pool service.shutdown(); } } class MyThread implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }