Detailed explanation of multithreading (Java.Thread)
Thread introduction
-
Multitasking multithreading
-
Common method calls and multithreading
-
Process: it is an execution process of program execution. It is a dynamic concept and the unit of system resource allocation
Thread thread: usually, a process can contain several threads, and each process contains at least one thread (main thread). Otherwise, it has no meaning. Thread is the unit of CPU scheduling and execution.
-
Note: many multithreads are simulated. Real multithreading refers to having multiple CPU s, 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, it has the illusion of executing at the same time.
Core concepts of this chapter
- Threads are independent execution paths
- When the program is running, even if it does not create its own thread, there will be multiple threads in the background, such as main thread and gc thread (garbage collection mechanism).
- main() is called the main thread, which is the system entry and is used to execute programs
- In a process, if multiple threads are opened up, the operation of threads is scheduled by the scheduler, which is closely related to the operating system. The order of precedence cannot be considered intervention.
- When operating on the same resource, there will be a problem of resource grabbing, and concurrency control needs to be added.
- Threads will bring additional overhead, such as CPU scheduling time and concurrency control overhead.
- Each thread interacts in its own working memory. Improper memory control board will cause inconsistent data
Thread creation
Three creation methods
- Thread (class): inherit thread class (key)
- Runnable interface: implement runnable interface (key)
- Callable interface: implement callable interface (understand)
Thread
(learning reminder: View jdk help documents)
-
The custom Thread class inherits the Thread class
-
Rewrite the run() method to write the thread execution body
-
Create a thread object and call the start() method to enable the thread
-
Threads do not necessarily execute immediately, and the CPU schedules them
-
practice
package com.LTF.Thread1.test1; //Thread creation method 1: inherit the thread class, rewrite the run() method, and call start to start the thread public class TestThread1 extends Thread{ @Override public void run() { //Method thread body for (int i = 0; i < 20; i++) { System.out.println("I'm learning code"+i); } } public static void main(String[] args) { //Main thread, main thread. //Create a thread object testThread1 TestThread1 testThread1 = new TestThread1(); //Call the start() method to start the thread testThread1.start(); for (int i = 0; i < 200; i++) { System.out.println("I'm learning multithreading..."+i); } } }
Case: download pictures
package com.LTF.Thread1.test1; //File toolkit class import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; //Practice Thread to realize multi-threaded synchronous downloading of pictures public class testThread2 extends Thread{ private String url; //Network picture address private String name ; //Saved files //Throw in with constructor public testThread2(String url,String name){ this.url=url; this.name=name; } @Override public void run() { //Override the run method, which is an execution body in a thread //The execution body of the download image thread WebDownloader webDownloader =new WebDownloader(); webDownloader.downloader(url,name); System.out.println("Downloaded file named"+name); } public static void main(String[] args) { //Three threads are created in the main method, T1, T2 and T3 testThread2 t1 =new testThread2("https://i0.hdslb.com/bfs/archive/65b588a85a9a98430ca609755f817e585d9360ed.jpg","1.jpg"); testThread2 t2 =new testThread2("https://i0.hdslb.com/bfs/archive/65b588a85a9a98430ca609755f817e585d9360ed.jpg","2.jpg"); testThread2 t3 =new testThread2("https://i0.hdslb.com/bfs/archive/65b588a85a9a98430ca609755f817e585d9360ed.jpg","3.jpg"); t1.start(); t2.start(); t3.start(); } } //Downloader class WebDownloader { //Download method public void downloader(String url,String name){ try { //The copyURLToFile method turns a web page address in the network into a file //You need to throw in a url and name 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"); } } }
Idea: we need to realize multi-threaded downloading of pictures,
1. First, a Downloader is written. There is a download method downloader in the downloader. The download method is completed through the copyURLToFile method in a FileUtil toolkit we imported. Here, we need to throw in two attributes: url and name
2. We need to use multithreading, so here let the testThread class inherit the thread class, encapsulate the two properties url (address of network picture) and name (name of saved file), and use the constructor to throw it in
3. When we inherit the thread class, we must rewrite the run() method in the thread class. The run() method is an executive body in the thread. Here, it is the executive body of the image download thread. We instantiate a downloader object to let the downloader object download images using two attributes through the download method
4. Create several thread () constructor objects in the main method, throw in two actual attributes, and finally start the thread through the start() method.
Implement Runnable
(learning tips: View JDK help documents)
-
Define the MyRunnable class to implement the Runnable interface
-
Implement the run() method and write the thread execution body
-
Create a thread object and call the start() method to start the thread
-
The Runnable object is recommended because of the limitations of Java single inheritance
-
practice
package com.LTF.Thread1.test1; //Create thread method 2: implement the runnable interface and rewrite the run method. The execution thread needs to drop into the runnable interface implementation class and call the start method public class TestThread3 implements Runnable{ @Override public void run() { //Method thread body for (int i = 0; i < 20; i++) { System.out.println("I'm learning code"+i); } } public static void main(String[] args) { //Create an implementation class object testThread3 for the runnable interface TestThread3 testThread3 = new TestThread3(); // //Create a thread object and start our thread agent through the thread object // Thread thread = new Thread(testThread3); // //Call the start() method to start the thread // thread.start(); //The above two sentences can be summarized as the following sentence new Thread(testThread3).start(); for (int i = 0; i < 200; i++) { System.out.println("I'm learning multithreading..."+i); } } }
Summary:
- Inherit Thread class
- Subclass inheritance has multithreading capability
- 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
Understanding concurrency problems
Concurrency occurs when multiple threads operate on the same resource
Example: buy a ticket
package com.LTF.Thread1.test1; //Multiple threads operate on the same object //Simulated ticket buying, multi person ticket buying //Problems found: when multiple threads operate on the same resource, the thread is unsafe and the data is disordered. public class TestThread4 implements Runnable{ private int ticketNum = 10; @Override public void run() { while(true){ if (ticketNum<=0){ break; } //Simulate the delay, otherwise the cpu will execute too fast try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->Bought a second"+ticketNum--+"Ticket"); } } public static void main(String[] args) { TestThread4 ticket = new TestThread4(); new Thread(ticket,"Xiao Ming").start(); new Thread(ticket,"Xiao Hong").start(); new Thread(ticket,"Small steel").start(); new Thread(ticket,"Scalpers").start(); } }
Example 2: simulated tortoise rabbit race
package com.LTF.Thread1.test1; public class Race implements Runnable{ //Use static to ensure that there is only one winner private static String winner; @Override public void run() { for (int i = 0; i <= 100; i++) { boolean flag = gameOver(i); //Exit the program if the game is over if(flag){ break; } //The rabbit is supposed to sleep, delay if(Thread.currentThread().getName()=="rabbit"&& i%10==0){ try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"-->Run away"+i+"rice"); } } //Judging who won the game, private boolean gameOver(int steps){ if(winner != null){ //Is there a winner and is the game over return true; } else if (steps == 100) { winner = Thread.currentThread().getName(); System.out.println("The 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(); } }
Implement Callable interface
(just understand, Thread and Runnable are the key points)
-
To implement the Callable interface, a return type is required
-
When overriding the call() method, you need to throw an exception
-
Create target object
-
Create execution service: ExecutorService ser = Executors.newFixedThreadPool(1);
-
Submit execution: Future result1 = ser.submit(t1);
-
Get result: boolean r1 = result1.get()// An exception needs to be thrown
-
Shut down the service: ser.shutdownNow();
Example: use the callable interface to download pictures
package com.LTF.Thread1.test2; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.concurrent.*; public class testCallable implements Callable<Boolean> { private String url; //Network picture address private String name ; //The name of the saved file //Throw in with constructor public testCallable(String url,String name){ this.url=url; this.name=name; } @Override public Boolean call() { //Override the run method, which is an execution body in a thread //The execution body of the download image thread WebDownloader webDownloader =new WebDownloader(); webDownloader.downloader(url,name); System.out.println("Downloaded file named"+name); return true; } public static void main(String[] args) throws ExecutionException, InterruptedException { //Three threads are created in the main method, T1, T2 and T3 testCallable t1 =new testCallable("http://i2.hdslb.com/bfs/face/83bb511365da513c55aa3d1958524f3b7db40684.jpg","1.jpg"); testCallable t2 =new testCallable("http://i2.hdslb.com/bfs/face/83bb511365da513c55aa3d1958524f3b7db40684.jpg","2.jpg"); testCallable t3 =new testCallable("http://i2.hdslb.com/bfs/face/83bb511365da513c55aa3d1958524f3b7db40684.jpg","3.jpg"); //1. Create execution service: ExecutorService ser = Executors.newFixedThreadPool(3); //2. Submission for implementation: Future<Boolean> result1 = ser.submit(t1); Future<Boolean> result2 = ser.submit(t2); Future<Boolean> result3 = ser.submit(t3); //3. Obtain results: boolean r1 = result1.get();//An exception needs to be thrown boolean r2 = result2.get(); boolean r3 = result3.get(); System.out.println(r1); System.out.println(r2); System.out.println(r3); //4. Shut down the service: ser.shutdownNow(); } } //Downloader class WebDownloader { //Download method public void downloader(String url, String name) { try { //The copyURLToFile method turns a web page address in the network into a file //You need to throw in a url and name 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"); } } }
Static proxy
Real role: focus on doing your own things
Agent role: it can help real characters do things that real characters can't do
Summary of static proxy mode:
Both the real object and the proxy object should implement the same interface, and the proxy object should proxy the real object,
example:
package com.LTF.Thread1.test3; //Simulated marriage public class StaticProxy { public static void main(String[] args) { You you = new You(); new WeddingCompany(you).Marry(); // WeddingCompany weddingCompany = new WeddingCompany(new You()); // weddingCompany.Marry(); } } //1. Marriage interface interface Marry{ //Marriage method void Marry(); } //Real character: you class You implements Marry{ @Override public void Marry() { System.out.println("I'm getting married. I'm very happy"); } } //Acting role: wedding company class WeddingCompany implements Marry{ //Declare a marriage agent target private Marry target; //Construction method public WeddingCompany(Marry target){ this.target = target; } @Override public void Marry() { before(); this.target.Marry(); after(); } private void after() { System.out.println("After marriage, the wedding company collects the balance"); } private void before() { System.out.println("Before marriage, the wedding company collects a deposit, arranges the wedding site and prepares for the wedding"); } }
Lambda expression
- Why use lambda expressions
- Avoid too many anonymous inner class definitions
- It can make your code look more concise
- Removed a pile of meaningless code, leaving only the core logic
Understanding 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.
//for example public interface Runnable{ public abstract void run(); }
-
For functional interfaces, we can create objects of the interface through lambda expressions
-
-
Summary:
- lambda expressions can only be reduced to one line if there is one line of code. If there are multiple lines, use code blocks.
- The premise is that the interface is a functional interface
- Parameter types can also be removed from multiple parameters. To remove them, remove them all and add parentheses.
package com.LTF.Thread1.testLambda; //Simplified reasoning of lamdba expression public class TestLambda { //3. Static internal class static class Want2 implements Iwant{ @Override public void lambda() { System.out.println("I want to eat...orange"); } } public static void main(String[] args) { Iwant w1 = new Want(); w1.lambda(); Iwant w2 =new Want2(); w2.lambda(); //4. Local internal class class Want3 implements Iwant{ @Override public void lambda() { System.out.println("I want to eat...banana"); } } Iwant w3 = new Want3(); w3.lambda(); //5. Anonymous inner class Iwant w4 = new Iwant() { @Override public void lambda() { System.out.println("I want to eat...peach"); } }; w4.lambda(); //6. Use lamdba expression to avoid class name and method name Iwant w5 = ()-> { System.out.println("I want to eat...pear"); }; w5.lambda(); //lamdba expressions can be expressed in one sentence without curly braces, and in multiple sentences with code blocks (enclosed in curly braces) } } //1. Write a functional interface: an interface with only one abstract method interface Iwant{ void lambda();//It does not need to be set as abstract. It is abstract inside the interface. } //2. Implementation class class Want implements Iwant{ @Override public void lambda() { System.out.println("I want to eat...apple"); } }
Five states of threads
Stop thread
- The stop() and destroy() methods provided by jdk are not recommended. [abandoned]
- It is recommended that the thread stop itself – > utilization times.
- It is recommended to use a flag bit to terminate the variable. When flag=false, the thread will be terminated.
- Example: let the main Thread stop by itself using the number of times, and let the Thread stop by using the flag bit
package com.LTF.ThreadState; //Test thread stopped, //1. It is recommended that the thread can stop normally, -- > for example, the number of utilization times, and dead loop is not recommended //2. It is recommended to use the flag bit //3. Do not use outdated methods such as stop or destroy, or methods not recommended by jdk public class testStop implements Runnable{ //1. First set a flag bit private Boolean flag = true; @Override public void run() { int i = 0; while(flag){ System.out.println("Thread is running..."+i++); } } //2. Set a public stop method to stop the thread and convert the flag bit to false; public void stop(){ this.flag = false; } public static void main(String[] args) { testStop t1 =new testStop(); new Thread(t1).start(); for (int i = 0; i < 1000; i++) { System.out.println("main is running..."+i); //When the main Thread runs to 900, stop the Thread if(i==900){ t1.stop(); System.out.println("The thread is about to stop..."+i); } } } }
Thread sleep
- sleep specifies the number of milliseconds the current thread is blocking
- Exception InterruptedException exists in sleep;
- After the sleep time reaches, the thread enters the ready state;
- sleep can simulate network delay, countdown and so on.
- Each object has a lock, and sleep will not release the lock;
The purpose of imitating network delay is to amplify the occurrence of the problem.
1000 ms = 1 second
Example 1: analog network delay:
package com.LTF.ThreadState; //Simulate network delay: the function is to amplify the occurrence of problems. If the cpu runs too fast, the occurrence of problems will be small public class testSleep1 implements Runnable{ private int ticketNum = 10; @Override public void run() { while(true){ if (ticketNum<=0){ break; } //Simulate the delay, otherwise the cpu will execute too fast try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->Bought a second"+ticketNum--+"Ticket"); } } public static void main(String[] args) { testSleep1 ticket = new testSleep1(); new Thread(ticket,"Xiao Ming").start(); new Thread(ticket,"Xiao Hong").start(); new Thread(ticket,"Small steel").start(); new Thread(ticket,"Scalpers").start(); } }
Example 2: analog Countdown:
package com.LTF.ThreadState; import java.text.SimpleDateFormat; import java.util.Date; //Simulate the countdown. public class testSleep2 { public static void main(String[] args) { //2. Get the current time of the system Date startTime = new Date(System.currentTimeMillis()); //Get the current system time while(true){ try { Thread.sleep(1000); System.out.println("The current system time is:"+new SimpleDateFormat("HH:mm:ss").format(startTime)); startTime=new Date(System.currentTimeMillis()); //Update time } catch (InterruptedException e) { e.printStackTrace(); } } //1. Countdown // try { // Time1(); // } catch (InterruptedException e) { // e.printStackTrace(); // } } public static void Time1() throws InterruptedException { int num = 10; while(true){ Thread.sleep(1000); System.out.println(num--); if(num<=0){ break; } } System.out.println("The bomb exploded, boom..."); } }
Thread yield
- Comity thread, which suspends the currently executing thread, but will not block
- Transition a thread from a running state to a ready state
- Rescheduling the CPU is not necessarily successful. The key is the CPU.
package com.LTF.ThreadState; public class testYield { public static void main(String[] args) { MyYield myYield =new MyYield(); new Thread(myYield,"a").start(); new Thread(myYield,"b").start(); } } class MyYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"Thread started"); Thread.yield();//Thread comity depends on CPU scheduling. Comity may not be successful. System.out.println(Thread.currentThread().getName()+"The thread stopped"); } }
Thread forced join
- join merge threads. After this thread completes execution, other threads will be executed, and other threads will be blocked.
- Think of it as a thread jumping in line.
- Exception InterruptedException exists in join();
example:
package com.LTF.ThreadState; public class testJoin implements Runnable{ public static void main(String[] args) throws InterruptedException { testJoin testJoin1 = new testJoin(); Thread thread = new Thread(testJoin1); thread.start(); for (int i = 0; i < 500; i++) { System.out.println("main Thread in execution"+i); if(i==200){ thread.join();//The main thread is blocked } } } @Override public void run() { System.out.println("VIP The thread came to jump the queue"); for (int i = 0; i < 100; i++) { System.out.println("VIP Thread execution"+i); } } }
Thread state observation
Thread.state enumeration type
Thread status. A thread can be in one of the following states:
- NEW
Threads that have not yet started are in this state. - RUNNABLE
The thread executing in the Java virtual machine is in this state. - BLOCKED
A thread that is blocked and waiting for a monitor lock is in this state. - WAITING
A thread that waits indefinitely for another thread to perform a particular operation is in this state. - TIMED_WAITING
A thread waiting for another thread to perform an operation depending on the specified waiting time is in this state. - TERMINATED
The exited thread is in this state.
A thread can only be in one state at a given point in time. These states are virtual machine states, and they do not reflect all operating system thread states.
package com.LTF.ThreadState; public class testState { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ for (int i = 0; i < 5; i++) { //Sleep for one second every time you run, and the thread is blocked try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } //Thread output System.out.println("#########"); }); //Observe thread status NEW Thread.State state = thread.getState();//Thread state System.out.println(state);//NEW //Thread start thread.start(); state = thread.getState();//Update thread status System.out.println(state);//Runnable //After thread startup while (state != Thread.State.TERMINATED){ //As long as the thread state is not equal to TERMINATED, that is, it will always output the state Thread.sleep(100);//Make a delay and don't output too fast state = thread.getState();//Status update System.out.println(state);//Status output } } }
Note: when the thread status is TERMINATED, it means that the thread has stopped, and the thread after stopping (death) cannot be started again. No matter it is interrupted or ended, once it enters the state of death, it cannot be started again.
Thread Priority
- Java provides a thread scheduler to monitor all threads that enter the state after startup. The thread scheduler determines which thread should 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 get priority in the following ways
- getPriority().setPriority(int xxx)
It is recommended to set the priority before start() scheduling. If you think which thread is more important when writing code, you can set the priority.
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 CPU scheduling.
package com.LTF.Thread1.testPriority; public class TestPriority { public static void main(String[] args) { //The priority of the direct output main thread is the default priority of 5 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); Thread t4 = new Thread(myPriority); Thread t5 = new Thread(myPriority); Thread t6 = new Thread(myPriority); t1.setPriority(3); t1.start(); t2.setPriority(Thread.MAX_PRIORITY); t2.start(); t3.setPriority(Thread.MIN_PRIORITY); t3.start(); t4.setPriority(Thread.NORM_PRIORITY); t4.start(); t5.start(); t6.setPriority(9); t6.start(); } } class MyPriority implements Runnable{ @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority()); } }
daemon thread
- Threads are divided into user threads and daemon threads
- The virtual machine must ensure that the user thread is completed, such as main()
- The virtual machine does not have to wait for the daemon thread to finish executing, such as gc() garbage collection thread
- For example, the background records the operation log, monitors the memory, and waits for garbage collection.
There is only one method, setDaemon() method, with parameters of true and false. The default is false.
package com.LTF.Thread1.testDaemon; 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. Set the god thread as the daemon thread. thread.start();//God thread start new Thread(you).start(); //Your thread starts } } class God implements Runnable{ @Override public void run() { while (true){ System.out.println("God has been watching over you"); } } } class You implements Runnable{ @Override public void run() { for (int i = 1; i < 35600; i++) { System.out.println("This is the second"+i+"Day, I spent this day happily!!!"); } System.out.println("======GoodBye,World======="); } }
Thread synchronization mechanism
-
Concurrency: the same object is operated by multiple threads at the same time
-
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 source access in the method, the lock mechanism synchronized 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, There are the following problems
- Holding a lock by one thread will cause other threads that need the lock to hang
- 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.
-
Although the thread safety problem is solved, the performance is lost.
Unsafe cases
-
Unsafe ticket buying
package com.LTF.SYN; //Unsafe ticket buying //If the thread is unsafe, there will be a negative number. When there is only one ticket left, three people will get it, and there will be a negative number. public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket buyTicket = new BuyTicket(); new Thread(buyTicket,"Xiao Hong").start(); new Thread(buyTicket,"Xiaomin").start(); new Thread(buyTicket,"Scalpers").start(); } } class BuyTicket implements Runnable{ private int ticketNum = 10; boolean flag = true; //Use the identification bit to stop the thread @Override public void run() { //1. Buy tickets while(flag){ buy(); } } //Buying method public void buy(){ //Judge whether there are tickets if(ticketNum <= 0){ flag = false; return;//Return without a ticket } //Use sleep to amplify the occurrence of things try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Buy it if you have a ticket System.out.println(Thread.currentThread().getName()+"Got the second"+ticketNum--+"Ticket"); } }
-
Unsafe bank account
package com.LTF.SYN; //Unsafe bank withdrawal //Negative number, thread unsafe public class UnsafeBank { public static void main(String[] args) { 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;//Account balance String name;//Account name //Construction method public Account(int money, String name) { this.money = money; this.name = name; } } //Bank, simulated withdrawal Drawing class Drawing extends Thread{ Account account;//account int drawingmoney; //Take money int nowmoney; //How much money do you have public Drawing(Account account,int drawingmoney,String name){ super(name); this.account=account; this.drawingmoney = drawingmoney; } @Override public void run() { //Determine whether there is enough money in the account if(account.money - drawingmoney < 0){ System.out.println(Thread.currentThread().getName()+"There's no money to take. You can give up"); return; } //Using sleep to set the delay try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Card balance = balance - money withdrawn account.money = account.money -drawingmoney; //Money in your hand = existing money + withdrawn money nowmoney = nowmoney + drawingmoney; System.out.println(account.name+"The balance is:"+account.money+"Ten thousand yuan"); //Thread.currentThread().getName() == this.getName() System.out.println(this.getName()+"Existing:"+nowmoney+"Ten thousand yuan"); } }
-
Thread unsafe collection
package com.LTF.SYN; //Collection of unsafe threads import java.util.ArrayList; import java.util.List; public class UnsafeList { public static void main(String[] args) { List<String> list =new ArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread(()-> list.add(Thread.currentThread().getName()) ).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } //The expected number of threads is 10000, but the result is not, indicating that the thread is unsafe System.out.println(list.size()); } }
Unsafe reason: it may be that if two threads add two arrays to the same location at the same time, one will be overwritten, so it is unsafe.
Synchronization method and synchronization block
-
Because we can use the private keyword to ensure that data objects can only be accessed by methods, we only need to propose a mechanism for methods. This mechanism is the synchronized keyword, which includes two uses: synchronized method and synchronized block:
Synchronization method: public synchronized void method(int args){ }
-
The synchronized method controls access to "objects". Each object corresponds to a lock. Each synchronized method must obtain the lock of the object calling the method before execution. Otherwise, the thread will block. Once the method is executed, it will monopolize the lock until the method returns. The blocked thread can obtain the lock and continue to execute.
-
Pitfalls: declaring a large method synchronized will affect efficiency.
-
Disadvantages of synchronization method: only the contents that need to be modified in the method need to be locked, otherwise too many locks will waste resources.
Synchronization block
-
Synchronization block: synchronized(Obj) {}
-
Obj is called synchronization monitor
- Obj can be any object, but it is recommended to use shared resources as synchronization monitors
- There is no need to specify a synchronization monitor in the synchronization method, because the synchronization monitor of the synchronization method is this, the object itself, or class.
-
Synchronization monitor execution
a. The first thread accesses, locks the synchronization monitor, and executes the code in it.
b. The second thread accesses and finds that the synchronization monitor is locked and cannot be accessed
c. After the first thread is accessed, unlock the synchronization monitor
d. The second thread accesses, finds that the synchronization monitor has no lock, and then locks and accesses.
Example: as above, unsafe ticket buying
//Add the synchronized keyword to the method called jointly by threads, change the method into a synchronized synchronized method, and lock this public synchronized void buy(){ //Judge whether there are tickets if(ticketNum <= 0){ flag = false; return;//Return without a ticket } //Use sleep to amplify the occurrence of things try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } //Buy it if you have a ticket System.out.println(Thread.currentThread().getName()+"Got the second"+ticketNum--+"Ticket"); } //The final result will not be that several threads grab a resource, but will run down one thread and one resource.
As above, unsafe bank accounts
//The resource operated by threads is the bank account, //The object of the lock is the amount of change, which needs to be added, deleted and modified. @Override public void run() { synchronized (account){ //Determine whether there is enough money in the account if(account.money - drawingmoney < 0){ System.out.println(Thread.currentThread().getName()+"There's no money to take. You can give up"); return; } //Using sleep to set the delay try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Card balance = balance - money withdrawn account.money = account.money -drawingmoney; //Money in your hand = existing money + withdrawn money nowmoney = nowmoney + drawingmoney; System.out.println(account.name+"The balance is:"+account.money+"Ten thousand yuan"); //Thread.currentThread().getName() == this.getName() System.out.println(this.getName()+"Existing:"+nowmoney+"Ten thousand yuan"); } }
As above, unsafe thread collection
//Lock the list and the thread is safe. The final result is 10000 for (int i = 0; i < 10000; i++) { new Thread(()->{ synchronized (list){ list.add(Thread.currentThread().getName()); } }).start(); }
CopyOnWriteArrayList
JUC (Java.util.concurrent) belongs to concurrent programming. It is a toolkit for processing threads. JDK1.5 began to appear.
concurrent and contract, and callable also belongs to this package.
The CopyOnWriteArrayList type itself is secure and does not need to be locked with synchronized
package com.LTF.SYN; import java.util.concurrent.CopyOnWriteArrayList; //Test JUC security type collection public class TestJUC { public static void main(String[] args) throws InterruptedException { CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread( ()->{ list.add(Thread.currentThread().getName()); }).start(); } Thread.sleep(3000); System.out.println(list.size()); } }
deadlock
- Multiple threads occupy some shared resources and wait for the resources occupied by other threads to run. As a result, two or more threads are waiting for each other to release resources and stop execution. When a synchronization block has "locks of more than two objects" at the same time, the problem of "deadlock" may occur.
- Four necessary conditions for deadlock generation:
- Mutex condition: a resource can only be used by one process at a time
- Request and hold condition: when a process is blocked by requesting resources, it will hold on to the obtained resources.
- Conditions of non deprivation: the resources obtained by the process cannot be forcibly deprived before they are used up.
- Circular waiting condition: a circular waiting resource relationship is formed between several processes.
- For the four necessary conditions of deadlock listed above, we can avoid deadlock as long as we find a way to break any one or more of them.
Lock
-
Since JDK 5.0, Java has provided a more powerful thread synchronization mechanism -- 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. Locks provide exclusive access to shared resources. Only one thread can Lock the Lock object at a time. Threads should obtain the Lock object before accessing shared resources.
-
**ReentrantLock (reentrant Lock) * * class implements Lock. It has the same concurrency and memory semantics as synchronized. ReentrantLock is commonly used in real thread safety control. It can display locking and releasing locks.
//try/catch is generally used to lock and release locks class A{ private final ReentrantLock lock = new ReenTrantLock(); public void m(){ try{ lock.lock(); //Lock //Thread safe code }finally{ lock.unlock(); //If there is an exception in the synchronization code, write unlock() to the finally statement block } } }
synchronized vs Lock
-
Lock is a display 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 has only code block locks, and synchronized has code block and method locks
-
Using Lock lock, the JVM will spend less time scheduling threads and perform better. And it has better extensibility (providing more subclasses)
-
Priority:
Lock > sync code block (entered the method body and allocated the response resources) > sync method (outside the method body)
Thread collaboration
Producer consumer issues
Using the management process method to solve the problem of producer and consumer, the concurrent cooperation model "producer / consumer model"
Producer: module responsible for production data (may be method, object, thread, process);
Consumer: module responsible for processing data (may be method, object, thread, process);
Buffer zone: consumers cannot directly use the producer's data. There is a buffer zone between them. The producer puts the produced data into the buffer zone, and consumers take out the data from the buffer zone.
example:
package com.LTF.SYN; //Testing: producer and consumer model -- "solving with buffer, pipe process method" public class TestPC { public static void main(String[] args) { SynContainer container = new SynContainer(); new Productor(container).start(); new Consumer(container).start(); } } //producer class Productor extends Thread{ SynContainer container; public Productor( SynContainer container){ this.container=container; } //Production method @Override public void run() { for (int i = 1; i < 100; i++) { container.push(new Chicken(i)); System.out.println("The producer is producing a third product"+i+"Chicken"); } } } //consumer class Consumer extends Thread{ SynContainer container; public Consumer( SynContainer container){ this.container=container; } //Consumer product method @Override public void run() { for (int i = 1; i < 100; i++) { System.out.println("Consumer is consuming the third"+container.pop().id+"Chicken"); } } } //product class Chicken { //Product number int id; public Chicken(int id) { this.id = id; } } //buffer class SynContainer{ //A container size is required Chicken[] chickens = new Chicken[10]; //Counter int count = 0; //The producer puts in the product, public synchronized void push(Chicken chicken){ //If the container is full, you need to wait for consumers to consume it first while(count == chickens.length){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //If it is not full, we will continue to put in the product chickens[count] =chicken; System.out.println("There is already in the buffer"+count+"Chicken"); count++; //Consumers can be informed of consumption this.notify(); } //Consumer products public synchronized Chicken pop(){ //Judge whether it can be consumed while (count == 0) { //When unable to consume (the actual quantity is 0), the consumer waits for production try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //If there are products count--; Chicken chicken = chickens[count]; //After the consumer takes a product, // Notify the producer to continue production and put it into the buffer this.notify(); return chicken; } }
Thread pool
- Background: resources that are often created and destroyed and use a large amount of resources, such as threads in concurrency, have a great impact on performance.
- Idea: create many threads in advance and put them into the thread pool. You can get them directly when you use them, and put them back into the pool after use. It can avoid frequent creation and destruction and realize reuse.
- Benefits:
- Improved response time (reduced time to create new threads)
- Reduce resource consumption (reuse, no need to create multiple times)
- Easy thread management:
- corePoolSize: the size of the core pool
- maximumPoolSize: maximum threads
- keepAliveTime: when the thread has no task, it will terminate after holding for a maximum time.
- Since JDK 5.0, Apis related to thread pool are provided: ExecutorService and Executors
- ExecutorService: the real thread pool interface. Common subclass ThreadPoolExecutor
- void execute(Runnable command): executes tasks and commands without return value. It is generally used to execute Runnable commands
- Future submit (clubletask): execute a task with a return value. It is generally used to execute Callable
- void shutdown(): closes the connection pool
- Executors: tool class, factory class of thread pool, which is used to create and return different types of thread pools
package com.LTF.SYN; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //Test thread pool public class TestPool { public static void main(String[] args) { //Create service, create thread pool //The newFixedThreadPool parameter is: thread pool size ExecutorService service = Executors.newFixedThreadPool(10); //implement service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); //Close connection pool service.shutdown(); } } class MyThread implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } } After the consumer takes a product, // Notify the producer to continue production and put it into the buffer this.notify(); return chicken; } }
Thread pool
- Background: resources that are often created and destroyed and use a large amount of resources, such as threads in concurrency, have a great impact on performance.
- Idea: create many threads in advance and put them into the thread pool. You can get them directly when you use them, and put them back into the pool after use. It can avoid frequent creation and destruction and realize reuse.
- Benefits:
- Improved response time (reduced time to create new threads)
- Reduce resource consumption (reuse, no need to create multiple times)
- Easy thread management:
- corePoolSize: the size of the core pool
- maximumPoolSize: maximum threads
- keepAliveTime: when the thread has no task, it will terminate after holding for a maximum time.
- Since JDK 5.0, Apis related to thread pool are provided: ExecutorService and Executors
- ExecutorService: the real thread pool interface. Common subclass ThreadPoolExecutor
- void execute(Runnable command): executes tasks and commands without return value. It is generally used to execute Runnable commands
- Future submit (clubletask): execute a task with a return value. It is generally used to execute Callable
- void shutdown(): closes the connection pool
- Executors: tool class, factory class of thread pool, which is used to create and return different types of thread pools
package com.LTF.SYN; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //Test thread pool public class TestPool { public static void main(String[] args) { //Create service, create thread pool //The newFixedThreadPool parameter is: thread pool size ExecutorService service = Executors.newFixedThreadPool(10); //implement service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); //Close connection pool service.shutdown(); } } class MyThread implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }