Multithreading
1. Basic concepts
Process and Thread
Program: an ordered collection of instructions and data. It has no running meaning. It is a static concept.
Process: it is an execution process of an executing program. It is a dynamic concept. It is the unit of system resource allocation.
A process can contain multiple threads (for example, you can hear sound, see images, and watch bullet screens in the video at the same time)
A process has at least one thread, otherwise it has no meaning to exist.
Thread: 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. Core concepts
- 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;
- main() is called the main thread, which is the entry of the system and is used to execute the whole program;
- In a process, if multiple threads are opened up, the operation of threads is scheduled by the scheduler. The scheduler is closely related to the operating system, and the sequence can not be interfered by human beings;
- 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 will cause data inconsistency
3. Thread creation
- Inherit the Thread class and override the run method
- Create Thread class
- Override the run() method
- Call start() to start the thread
//Thread creation method 1: inherit the thread class, rewrite the run() method, and call start() to start the thread public class Test01 extends Thread{ @Override public void run() { //run method thread body for (int i = 0; i <20; i++) { System.out.println("I'm looking at the code"); } } public static void main(String[] args) { //main thread //Create a thread object Test01 t= new Test01(); // t.run(); Call the run () method, execute the run method body, and then execute the main method body //Call the start() method to start the thread and execute at the same time t.start(); for (int i = 0; i < 2000; i++) { System.out.println("I'm learning multithreading"+i); } } }
Summary: thread startup is not necessarily executed immediately, but is scheduled by the CPU
- Implement Runnable interface
a. Implement Runnable interface
b. Override the run() method
c. The execution thread needs to create a runnable interface implementation class and call the start() method
public class Test02 implements Runnable { @Override public void run() { for (int i = 0; i < 20; i++) { System.out.println("Run thread" + i); } } public static void main(String[] args) { Thread thread = new Thread(new Test02()); thread.start(); for (int i = 0; i < 20; i++) { System.out.println("Run main thread" + i); } } }
Buy a train ticket
public class TestTread implements Runnable { //Number of votes private int ticketNums = 10; @Override public void run() { while(true){ if(ticketNums<=0){ break; } //Analog delay try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->Got the second"+ticketNums-- +"ticket"); } } public static void main(String[] args) { TestTread ticket = new TestTread(); new Thread(ticket,"Xiao Ming").start(); new Thread(ticket,"teacher").start(); new Thread(ticket,"cattle").start(); } }
Image download [use Maven project, do not download common IO package]
public class WebDownloader implements Runnable { private String url; private String name; public WebDownloader(String url, String name) { this.url = url; this.name = name; } public void run() { DownLoadeer downLoadeer = new DownLoadeer(); downLoadeer.Down(url,name); System.out.println("Printed" + name); } public static void main(String[] args) { WebDownloader webDownloader1 = new WebDownloader("https://img14.360buyimg.com/n0/jfs/t1/55022/14/17084/127324/613598e6E8645c385/20fa4394e07e7506.jpg "," mouse. jpg "); WebDownloader webDownloader2 = new WebDownloader("https://Img14.360buyimg. COM / N0 / JFS / T1 / 6521 / 19 / 15591 / 164485 / 6157279e424120d1 / 6d9a67ac840a4271. jpg "," flat plate. jpg "); WebDownloader webDownloader3 = new WebDownloader("https://img14.360buyimg.com/n0/jfs/t1/164028/13/19810/141210/607d328aE3b9319a1/b3a14384c998ebd2.jpg "," mobile phone. jpg "); new Thread(webDownloader1).start(); new Thread(webDownloader2).start(); new Thread(webDownloader3).start(); } } class DownLoadeer{ public void Down(String url,String name){ try { FileUtils.copyURLToFile(new URL(url),new File(name)); }catch (Exception e){ e.printStackTrace(); System.out.println("io Abnormal, Down There is a problem with the method"); } } }
Summary: the difference between the above two
- Inherit Thread class:
- The subclass inherits the Thread class and has multithreading capability
- Start thread: subclass object. start()
- Not recommended: avoid the limitation of OOP single inheritance
- Implement Runnable interface:
- The implementation of Runnable interface has multithreading capability
- Start thread: new thread (implementation class object). start()
- Recommended: avoid the limitation of single inheritance and make it convenient for the same object to be used by multiple threads
- Implement Callable interface
- Implement Calleble interface
- Override call() method
- Create execution service
ExecutorService ser = Executors.newFixedThreadPool(Number of threads);
- Submit for execution
Future<return type> r = ser.submit(Thread name);
- Get results
type res=r.get();
- Shut down service
ser.shutdownNow();
Summary:
Advantages: 1. Return value can be defined; 2. Exception can be thrown
Disadvantages: relatively troublesome
4. Static proxy
——Multithreading underlying implementation principle
Example: real role: you; agent role: wedding company; marriage: realize marriage interface
public class StaticProxy { public static void main(String[] args) { WeddingCompany company = new WeddingCompany(new You()); company.happyMarry(); } } interface Marry{ void happyMarry(); } //Real role class You implements Marry{ @Override public void happyMarry() { System.out.println("I'm so happy to be married!"); } } //Acting role to help you get married class WeddingCompany implements Marry{ private Marry target; public WeddingCompany(Marry target){ this.target = target; } @Override public void happyMarry() { before(); this.target.happyMarry(); after(); } private void after() { System.out.println("After marriage, the final payment"); } private void before() { System.out.println("Before marriage, arrange the scene"); } }
Summary: both real objects and proxy objects should implement the same interface, and proxy objects should represent real roles
Advantages: proxy objects can do many things that real objects can't do
Real objects focus on their own things
In combination with threads:
new Thread(t).start(); new WeddingCompany(new You()).happyMarry();
Runnable - > Mary interface
Thread - > weddingcompany is the agent
t -- > New you() target object (real character)
5. Lambda expression
- In essence, it belongs to the concept of functional programming
1. Function
- Avoid too many anonymous inner class definitions
- Make the code look simple
- Simplify the code, leaving only the core logic
2. Functional interface
Definition: 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
3. Simple derivation of lambda
/** * Derivation of Lambda expressions * @author DELL * */ public class TestLambda { //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 lambda4"); } } like = new Like3(); like.lambda(); //5. Anonymous inner class like = new Ilike() { @Override public void lambda() { System.out.println("i like lambda5"); } }; 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 lambda"); } }
public class TestLambda2 { public static void main(String[] args) { ILove love = null; //1.lambda stands for simplification love = (int a)->{ System.out.println("LOvee"+ a); }; //Simplification 1: parameter type love = (a)->{ System.out.println("LOvee"+ a); }; //Simplify 2: simplify parentheses love = a->{ System.out.println("LOvee"+ a); }; //Simplify 3: simplify curly braces love = a-> System.out.println("LOvee"+ a); love.love(205); } } interface ILove{ void love(int a); }
Summary:
- lambda expressions can only be reduced to one line if there is only one line of code. If there are multiple lines, they are wrapped in code blocks.
- The premise of lambda expression is that the interface is functional.
- Parameter types can also be removed from multiple parameters. To remove them, remove them all and add parentheses.
6. Thread stop
1. Thread status
2. Method of thread stop
- It is recommended that threads stop normally - > utilization times, and dead loops are not recommended
- It is recommended to use flag bit - > set a flag bit
- Do not use outdated methods such as stop or destroy, or methods that are not recommended by JDK
public class TestStop implements Runnable{ //1. Set a flag bit private boolean flag = true; @Override public void run() { int i = 0; while(flag){ System.out.println("run...Thread"+ i++); } } //2. Set a public method to stop the thread and convert the flag bit public void stop(){ this.flag = false; } public static void main(String[] args) { TestStop stop = new TestStop(); new Thread(stop).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 stop.stop(); System.out.println("The thread stopped"); } } } }
7. Thread sleep()
- Sleep (time) specifies the number of milliseconds that the current thread is blocked;
- Exception InterruptedException exists in sleep;
- After the sleep time reaches, the thread enters the ready state;
- sleep can simulate network delay, countdown, etc;
- Each object has a lock, and sleep does not release the lock.
Example 1: analog delay: TestThread Simulating the role of network delay: amplifying the occurrence of the problem
//Analog countdown public class TestSleep1 { public static void main(String[] args) { try { tenDown(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void tenDown() throws InterruptedException { int num = 10; while(true){ Thread.sleep(1000); System.out.println(num--); if(num<=0){ break; } } } }
//Print system current time public class TestSleep2 { public static void main(String[] args) { Date startTime = new Date(System.currentTimeMillis()); //Get the current system time 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(); } } } }
8. Thread comity - yield()
- Comity thread, which allows the currently executing thread to pause without blocking;
- Change the thread from running state to ready state;
- Let the CPU reschedule. Comity is not necessarily successful. It depends on the CPU mood.
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 starts execution"); Thread.yield(); //Comity System.out.println(Thread.currentThread().getName()+"Thread stop execution"); } }
9. Thread enforcement - join()
- join merge threads. After this thread is executed, other threads will be executed, and other threads will be blocked;
- Imagine jumping in line
public class TestJoin implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("thread VIP coming"+i); } } public static void main(String[] args) throws InterruptedException { TestJoin testJoin = new TestJoin(); Thread thread = new Thread(testJoin); //Main thread for (int i = 0; i < 1000; i++) { if(i == 200){ thread.start(); thread.join(); //Jump in line } System.out.println("main"+i); } } }
10. Observe thread status
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 //Start after observation thread.start(); //Start thread state = thread.getState(); System.out.println(state); System.out.println(); //Run while(state != Thread.State.TERMINATED){ //As long as the thread does not stop, it always outputs the state Thread.sleep(100); state = thread.getState(); //Update thread status System.out.println(state); //Output status //thread.start(); An error is reported because the dead thread can no longer be started } } }
11. 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;
- Use the following methods to change or obtain priority
- getPriority.setPriority(int xxx)
public class TestPriority { public static void main(String[] args) { //Default priority of main thread 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); //Set priority before starting t1.start(); t2.setPriority(1); t2.start(); t3.setPriority(4); t3.start(); t4.setPriority(Thread.MAX_PRIORITY); t4.start(); // t5.setPriority(-1); //Exception in thread "main" java.lang.IllegalArgumentException // t5.start(); // // t6.setPriority(11); //Exception in thread "main" java.lang.IllegalArgumentException // t6.start(); } } class MyPriority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority()); } }
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. It all depends on the CPU scheduling.
12. Daemon thread
- Threads are divided into user threads and daemon threads
- The virtual machine must ensure that the user thread is completed (e.g., main)
- The virtual machine does not have to wait for the daemon thread to finish executing (for example, recording operation logs in the background, monitoring memory, garbage collection...)
//God protects you public class TestDaemon { public static void main(String[] args) { God god = new God(); You2 you = new You2(); Thread thread = new Thread(god); thread.setDaemon(true); //The default false indicates that it is a user thread, and normal threads are user threads thread.start(); //God daemon thread start 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 You2 implements Runnable{ @Override public void run() { for (int i = 0; i < 36500; i++) { System.out.println("You live happily all your life"); } System.out.println("=====GoodBye World!======"); } }
13. Thread synchronization mechanism
Concurrency: the same object is operated by multiple threads at the same time (for example, tens of thousands of people rob tickets at the same time)
When dealing with multithreading, multiple threads access the same object(Concurrent),And some threads also want to modify this object. In this case, thread synchronization is required. 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 be used, and then use the next thread.
Conditions for thread synchronization: queue + lock
19. Three major unsafe cases
[1. Buy tickets]
//Thread unsafe, negative number public class UnsafeBuyTicket implements Runnable{ //Number of votes private int ticketNums = 10; boolean flag = true; //External stop method @Override public void run() { while(flag){ buy(); } } public void buy(){ //Judge whether there are tickets if(ticketNums<=0){ flag = false; return; } //Analog delay try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->Got the second"+ticketNums-- +"ticket"); } public static void main(String[] args) { UnsafeBuyTicket ticket = new UnsafeBuyTicket(); new Thread(ticket,"Xiao Ming").start(); new Thread(ticket,"teacher").start(); new Thread(ticket,"cattle").start(); } }
[2. Unsafe bank]
public class UnsafeBank { public static void main(String[] args) { Account account = new Account(100,"fund"); Drawing you = new Drawing(account,50,"you"); Drawing wo = new Drawing(account,100,"wo"); you.start(); wo.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 int drawingMoney; //How much did you withdraw int nowMoney; //How much money do you have now public Drawing(Account account, int drawingMoney, String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } //Withdraw money @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(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Card balance = balance - withdrawn money account.money = account.money - drawingMoney; //Money in hand nowMoney = nowMoney + drawingMoney; System.out.println(account.name+"The balance is:"+account.money); System.out.println(this.getName()+"Money in hand:"+nowMoney); } }
[3. Unsafe collection]
public class UnsafeList { public static void main(String[] args) throws InterruptedException { List<String> list = new ArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } //Thread.sleep(500); System.out.println(list.size()); } } //Output: 9999
20. Synchronization method and synchronization method block
◆Because we can pass private Keyword to ensure that data objects can only be accessed by methods,Therefore, we only need to propose a set of mechanism for the method,This mechanism is synchronized keyword,It includes two uses:synchronized Methods and synchronized block Synchronization method: public synchronized void method(int args) } ◆synchronized Method to control access to the object,Each object corresponds to a lock,each synchronized Methods must obtain the lock of the object calling the method in order to execute,Otherwise, the thread will block, and once the method is executed,Just monopolize the lock,The lock is not released until the method returns,Only later blocked threads can obtain this lock,Continue. defect:If a large method is declared as synchronized Will affect efficiency
Only the contents that need to be modified in the method need to be locked, otherwise resources will be wasted
◆Synchronization block: synchronized (Obj){} ◆Obj It's called a synchronization monitor ◆Obj Can be any object,However, shared resources are recommended as synchronization monitors ◆You do not need to specify a synchronization monitor in the synchronization method,Because the synchronization monitor of the synchronization method is this , It's the object itself,Or class [Explanation in reflection] ◆Synchronization monitor execution 1.First thread access,Lock synchronization monitor,Execute the code. 2.Second thread access,Synchronization monitor found locked,cannot access. 3.First thread access completed,Unlock sync monitor 4.The second thread accesses and finds that the synchronization monitor has no lock,Then lock and access
Modify three unsafe cases as safe:
[1. Buy tickets]
public class UnsafeBuyTicket implements Runnable{ //Number of votes private int ticketNums = 10; boolean flag = true; //External stop method @Override public void run() { while(flag){ buy(); } } //synchronized synchronization method, this object public synchronized void buy(){ //Judge whether there are tickets if(ticketNums<=0){ flag = false; return; } //Analog delay try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->Got the second"+ticketNums-- +"ticket"); } public static void main(String[] args) { UnsafeBuyTicket ticket = new UnsafeBuyTicket(); new Thread(ticket,"Xiao Ming").start(); new Thread(ticket,"teacher").start(); new Thread(ticket,"cattle").start(); } }
[2. Withdrawal]
public class UnsafeBank { public static void main(String[] args) { Account account = new Account(200,"fund"); Drawing you = new Drawing(account,50,"you"); Drawing wo = new Drawing(account,100,"wo"); you.start(); wo.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 int drawingMoney; //How much did you withdraw int nowMoney; //How much money do you have now public Drawing(Account account, int drawingMoney, String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } //Withdraw money @Override public void run() { synchronized (account){ //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(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Card balance = balance - withdrawn money account.money = account.money - drawingMoney; //Money in hand nowMoney = nowMoney + drawingMoney; System.out.println(account.name+"The balance is:"+account.money); System.out.println(this.getName()+"Money in hand:"+nowMoney); } } }
[3. Set]
public class UnsafeList { public static void main(String[] args) throws InterruptedException { List<String> list = new ArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ synchronized (list){ list.add(Thread.currentThread().getName()); } }).start(); } Thread.sleep(500); System.out.println(list.size()); } } //Output: 10000
[4. Test JUC safety set]
public class TestJUC { public static void main(String[] args) { CopyOnWriteArrayList<String> copy = new CopyOnWriteArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ copy.add(Thread.currentThread().getName()); }).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(copy.size()); } } //Output: 10000
21. Deadlock
1. Definitions
Multiple threads each occupy one-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,All stop execution. When a synchronization block has "locks of more than two objects" at the same time,The problem of "deadlock" may occur.
//Deadlock: multiple threads hold each other's required resources public class DeadLock { public static void main(String[] args) { Makeup m1 = new Makeup(0,"Xiao Hei"); Makeup m2 = new Makeup(1,"Xiaobai"); m1.start(); m2.start(); } } //Lipstick class Lipstick{ } //mirror class Mirror{ } //Make up class Makeup extends Thread{ //There is only one resource needed. Use static to ensure that there is only one static Lipstick lipstick = new Lipstick(); static Mirror mirror = new Mirror(); int choice; //choice String name; //People who use cosmetics public Makeup(int choice, String name) { this.choice = choice; this.name = name; } @Override public void run() { //Make up try { makeup(); } catch (InterruptedException e) { e.printStackTrace(); } } //Makeup, holding each other's locks, is to get each other's resources private void makeup() throws InterruptedException { if(choice ==0){ synchronized (lipstick){ //Get lipstick lock System.out.println(this.name+"Get lipstick lock"); Thread.sleep(1000); } synchronized (mirror){ //I want to get the lock of the mirror in a second System.out.println(this.name+"Get the lock of the mirror"); } }else{ synchronized (mirror){ //Get the lock of the mirror System.out.println(this.name+"Get the lock of the mirror"); Thread.sleep(2000); } synchronized (lipstick) { //I want to get the lock of lipstick in two seconds System.out.println(this.name + "Get lipstick lock"); } } } }
Solution: take out the synchronization code block and don't two people hold a lock at the same time.
private void makeup() throws InterruptedException { if(choice ==0){ synchronized (lipstick){ //Get lipstick lock System.out.println(this.name+"Get lipstick lock"); Thread.sleep(1000); } synchronized (mirror){ //I want to get the lock of the mirror in a second System.out.println(this.name+"Get the lock of the mirror"); } }else{ synchronized (mirror){ //Get the lock of the mirror System.out.println(this.name+"Get the lock of the mirror"); Thread.sleep(2000); } synchronized (lipstick) { //I want to get the lock of lipstick in two seconds System.out.println(this.name + "Get lipstick lock"); } } }
2. Deadlock avoidance method
- 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.
Just destroy one of them. Deadlock can be avoided.
22.LOCK
◆from JDK 5.0 Start, Java Provides a more powerful thread synchronization mechanism_-Synchronization is achieved by explicitly defining the synchronization lock object. Use of synchronization lock Lock Object acts 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, with only one thread pair at a time Lock Object is locked, and the thread should obtain the lock before accessing the shared resource Lock object ◆ReentrantLock Class implements Lock ,It has and synchronized The same concurrency and memory semantics are commonly used in thread safety control ReentrantLock,You can explicitly add and release locks.
Examples of safe ticket buying:
class TestLock2 implements Runnable { int ticketNums = 10; //Define Lock lock private final ReentrantLock lock = new ReentrantLock(); @Override public void run() { while (true) { try { lock.lock(); //Lock if (ticketNums > 0) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "-->Got the second" + ticketNums-- + "ticket"); } else { break; } }finally { //Unlock lock.unlock(); } } } public static void main(String[] args) { new Thread(new TestLock2(),"Yellow Cattle").start(); } }
Note: if you need to throw an exception, unlock() needs to be written in the finally {} block
synchronized vs Lock
Lock Is an explicit lock(Manually open and close the lock. Don't forget to close the lock) synchronized It is an implicit lock, which is automatically released out of the scope ◆Lock Only code block locks, synchronized There are code block locks and method locks ◆use Lock Lock, JVM It will take less time to schedule threads for better performance. And it has better scalability(Provide more subclasses) ◆Priority order: Lock >Synchronous code block(It has entered the method body and allocated corresponding resources) >Synchronization method(Outside the method body)
23. Thread collaboration producer consumer model
1. Thread communication
(1) Application scenario: producer and consumer issues
◆ it is assumed that only - pieces of products can be stored in the warehouse, the producer will put the produced products into the warehouse, and the consumer will take away the products in 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 in the warehouse again
(2) Analysis:
This is a thread synchronization problem. Producers and consumers share the same resource, and producers and consumers are interdependent and conditional on each other
◆ for producers, inform consumers to wait before producing products, and inform consumers to consume immediately after producing products
◆ for consumers, after consumption, inform producers that consumption has ended and new products need to be produced for consumption
◆ in producer consumer issues, synchronized is not enough
◆ synchronized can prevent concurrent updating of the same shared resource and realize synchronization
◆ synchronized cannot be used to realize message transmission (Communication) between different threads
(3) Solution:
Concurrent collaboration model "producer / consumer model" – >
a. Pipe program method
◆ producer: module responsible for production data (may be method, object, thread, process);
◆ consumers: modules responsible for processing data (may be methods, objects, threads, processes);
◆ 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, and the consumer takes out the data from the buffer
public class GuanCheng { public static void main(String[] args) { SynContainer synContainer = new SynContainer(); new Productor(synContainer).start(); new Consumer(synContainer).start(); } } //producer class Productor extends Thread{ SynContainer container; public Productor(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; } //consumption @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println("Consumption----The first"+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[20]; //Container counter int count = 0; //The producer puts in the product public synchronized void push(Chicken chicken){ //If the container is full, it needs to wait for consumers to consume if(count == chickens.length){ //Inform consumers of consumption, production and waiting try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //If it is not full, we need to throw in the product chickens[count] = chicken; count++; //Consumers can be informed of consumption this.notifyAll(); } //Consumer products public synchronized Chicken pop(){ //Judge whether it can be consumed if(count == 0){ //Wait for the producer to produce try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //Take out the product if you can consume it count--; Chicken chicken = chickens[count]; //The producer can be informed of consumption this.notifyAll(); return chicken; } }
b. Signal lamp method
public class xinhao { 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 < 20; i++) { if(i%2==0){ this.tv.play("Happy base camp"); }else{ this.tv.play("make progress every day"); } } } } //Consumer audience class Watcher extends Thread{ TV tv; public Watcher(TV tv) { this.tv = tv; } @Override public void run() { for (int i = 0; i < 20; i++) { tv.watch(); } } } //Products -- programs class TV{ //The actor performs and the audience waits for T //The audience watched and the actors waited for F String voice; //perform boolean flag = true; //perform public synchronized void play(String voice){ if(!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("The actors performed:" + voice); //Inform the audience to watch this.notifyAll(); //Notification wake up this.voice = voice; this.flag = !this.flag; } //watch public synchronized void watch(){ if(flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Watched:" + voice); //Inform the actors to perform this.notifyAll(); this.flag = !this.flag; } }
24. Thread pool
Use thread pool ◆background:Resources that are often created and destroyed and used heavily, such as threads in concurrency, have a great impact on performance. ◆thinking:Create multiple threads in advance, put them into the thread pool, obtain them directly when using them, and put them back into the pool after use. It can avoid frequent creation, destruction and reuse, which is similar to public transportation in life. ◆benefit: Improve response speed(Reduced time to create new threads) Reduce resource consumption(Reuse threads in the thread pool without creating them every time) Easy thread management corePoolSize: Size of core pool maximumPoolSize:Maximum number of threads keepAliveTime: When a thread has no task, how long will it last at most and then terminate ◆JDK 5.0 Thread pool correlation is provided API: ExecutorService and Executors ◆ExecutorService: Real thread pool interface. Common subclasses ThreadPoolExecutor void execute(Runnable command) :Perform tasks/command,No return value, generally used to execute Runnable Future submit(Callable task):Perform tasks,There is a return value, which is generally used to execute Callable void shutdown() :Close connection pool ◆Executors: Tool class and thread pool factory class, which are used to create and return different types of thread pools
public class TestPool { public static void main(String[] args) { //1. Create service and thread pool ExecutorService service = Executors.newFixedThreadPool(10); //The parameter is the thread pool size //implement service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); //2. Close the connection service.shutdown(); } } class MyThread implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }