Introduction to threads and processes
Thread: an application that runs in memory. Each process has its own independent memory space. A process can have multiple threads. For example, in Windows system, a running XX Exe is a process.
Process: an execution task (control unit) in a process, which is responsible for the execution of programs in the current process. A process can run multiple threads, but there is at least one thread in a process, otherwise it has no meaning. Multiple threads can share data. Thread is the smallest unit of CPU scheduling and execution.
Benefits of multithreading:
Can improve CPU utilization. In multithreaded programs, when a thread has to wait, the CPU can run other threads instead of waiting, which greatly improves the efficiency of the program. In other words, a single program is allowed to create multiple threads executing in parallel to complete their respective tasks
Disadvantages:
-Threads are also programs, so threads need to occupy memory. The more threads, the more memory they occupy;
-Multithreading needs coordination and management, so CPU time is required to track threads;
-The access to shared resources between threads will affect each other, and the problem of competing for shared resources must be solved
Calling the run() method is different from calling the start() method
The start() method is used to start the thread, and the run() method is used to execute the runtime code of the thread. run() can be called repeatedly, while start() can only be called once.
start() method to start a Thread, which really realizes multi-threaded operation. Calling the start() method does not need to wait for the execution of the body code of the run method, but can directly continue to execute other codes; At this time, the Thread is in the ready state and is not running. Then, the Thread class calls the method run() to complete its running state. The run() method ends and the Thread terminates. Then the CPU schedules other threads.
The run() method is in this thread. It is only a function in the thread, not multithreaded. If you call run() directly, it is equivalent to calling an ordinary function. The run() method to be used directly must wait for the execution of the run() method to execute the following code. Therefore, there is only one execution path and there is no thread feature at all. Therefore, the start() method should be used instead of the run() method during multithreading execution.
2. Four ways to create threads
1. Inherit Thread class
2. Implement Runnable interface
3.Callaable interface
4. Create thread pool
1. Inherit Thread class
- Inherit Thread class
- Override the run() method
- Create a thread object and call the start() method to start
Not recommended: avoid the limitation of oop single inheritance
2. Implement Runnable interface
- Implement Runnable interface
- Override the run() method
- Create a thread object and start the thread through the thread object
- Call the stert() method
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
3. Implement Callable interface
- Implement the callable interface
- Override the call() method, which has a return value
- Create and execute services through threads
- Get thread return value
- Close return value
Static proxy
You: what a role
Wedding company: represent you and deal with the marriage
Marriage: just implement the marriage interface
It's true that both object and proxy object should implement the same interface
The proxy object should represent the real role
The advantage is that the proxy object can do many things that the real object can't do
Real objects focus on doing their own things
//summary //Both real objects and proxy objects should implement the same interface //The proxy object should represent the real role //Advantage: the advantage is that the proxy object can do many things that the real object can't do //Real objects focus on doing their own things public class StaticProxy { public static void main(String[] args) { You you = new You(); //Your marriage new Thread(() -> System.out.println("love you")).start(); new WeddingCompany(new You()).HappyMarry(); // WeddingCompany windowConstants = new WeddingCompany( you); windowConstants.HappyMarry(); } } interface Marry{ void HappyMarry(); } //Real role class You implements Marry { public void HappyMarry() { System.out.println("Get married!!!"); } } //Acting role to help you get married class WeddingCompany implements Marry { // Agent who -- > real target role private Marry target; public WeddingCompany(Marry target) { this.target = target; } public void HappyMarry() { befotr(); this.target.HappyMarry();//Real object call after(); } private void befotr() { System.out.println("Before marriage"); } private void after() { System.out.println("after marriage i"); } }
Status of the thread
New thread() -- > create state -- > call start() -- > ready state -- > wait for cpu scheduling -- > running state -- > dead state
New thread() -- > create state call start() -- > ready state (wait for cpu scheduling, call sleep or wait or synchronization lock) - > blocking state (re-enter the ready state after blocking, wait for cpu scheduling) - -- > ready state -- > running state (enter the running state, the thread will actually execute the code block of the thread body) - > death state (the thread is interrupted or terminated. Once it enters the dead state, it cannot be started again)
Thread method
Stop thread
It is recommended that the thread stop itself
It is recommended to use a flag bit to terminate the variable, put flag=false, and the thread terminates
package state; public class TestStop implements Runnable { // 1. Set an identification bit private boolean flag = true; @Override public void run() { int i = 0; while (flag) { System.out.println("run...Thread" + i); } } // Set the exposed method to stop the thread and convert the bit ID 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("Thread stop"); } } } }
Thread sleep
- sleep(1000) specifies the current thread blocking time of 1000 milliseconds
- Exception in sleep: InterruptedException
- When the sleep time arrives, the thread enters the ready state
- sleep can simulate network delay
- Every object has a lock, and sleep will not release the lock
package state; //Past current system time import java.text.SimpleDateFormat; import java.util.Date; public class TestSleep { public static void main(String[] args) { // Print current time Date startTime = new Date(System.currentTimeMillis()); // Get current system time while (true) { try { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime)); Date date = new Date(System.currentTimeMillis());//Update current time } catch (InterruptedException e) { e.printStackTrace(); } } }} //Analog countdown public class TestSleep { 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; } } } }
Thread comity
- Pause the currently executing thread without blocking it
- The thread changes from running state to ready state
- Rescheduling the CPU may not succeed
package state; //Comity test 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() + "Start execution"); Thread.yield(); //Comity System.out.println(Thread.currentThread().getName()+"Thread stop"); } }
Join
Join merge threads, wait for this thread to finish executing, and then execute other threads, and other threads will block (think about jumping in line)
package state; //Test Join public class TestJoin implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.err.println("vip insert-----Team" + i); } } public static void main(String[] args) throws InterruptedException { // Start thread TestJoin testStop = new TestJoin(); Thread thread = new Thread(testStop); // Main thread for (int i = 0; i < 1000; i++) { if (i == 200) { thread.start(); thread.join();//Cut in line } System.out.println("main" + i); } } }
Thread state observation
Thread.State
package state; //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 // Observe after startup thread.start();//Start thread state = thread.getState(); System.out.println(state); //Run while (state != Thread.State.TERMINATED) { //As long as the thread does not terminate, it will always output the state Thread.sleep(100); state = thread.getState(); //Update thread status System.out.println(state); //Output status } // thread.start(); // A thread can only be started once. It cannot be started again after the thread dies } }
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 is expressed in numbers, from 0 to 10
- MAX_PRIORITY is 10, which is the highest priority of the thread;
- MIN_ The priority value is 1, which is the lowest priority of the thread;
- NORM_ The priority value is 5, which is the priority of the middle position of the thread
Use getPriority(),setPriority(int x), get and change the thread priority
Low thread priority only means that the probability of obtaining scheduling is low, not that it will not be adjusted if the priority is low. It depends on the scheduling of CPU. It is possible that CPU will schedule those with low priority (performance inversion)
package state; //Test thread priority public class TestPriority extends Thread{ public static void main(String[] args) { // The priority of main thread is 5 by default 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); // Set priority at startup t1.start(); t2.setPriority(1); t2.start(); t3.setPriority(4); t3.start(); t4.setPriority(Thread.MAX_PRIORITY); //MAX_PRIORITY == 10 t4.start(); t5.setPriority(11); t5.start(); } } class MyPriority implements Runnable { @Override public void run() { 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 (main()) is completed
- The virtual machine does not have to wait for the daemon thread (gc()) to finish executing
- Record operation logs in the background, monitor memory, garbage collection, etc
package state; import java.util.concurrent.Callable; //Test the daemon thread, and God will guard you public class TestDeamo { 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 user threads. Normal threads are user threads thread.start(); //God guard start new Thread(you).start();//You start the y user thread } } //lord class God implements Runnable { @Override public void run() { while (true) { System.out.println("God is with you"); } } } //you class You implements Runnable { @Override public void run() { for (int i = 0; i < 365000; i++) { System.err.println("You live happily all your life"); } System.err.println("goodby world"); } }
Thread synchronization
Multiple threads operate on the same resource
Concurrency: the same object is operated by multiple threads at the same time (buying tickets)
Thread synchronization:
In the display situation, the most natural solution to the problem of "using one resource and multiple people want to use it" is queuing (queue)
When dealing with multithreading, when multiple threads access the same object (concurrent), and some threads want to modify the object, thread synchronization is required. Thread synchronization is actually a waiting mechanism. Multiple threads that need to access the object at the same time enter the waiting pool of the object to form a queue, wait for the previous thread to use it, and then use it again for the next thread
Thread synchronization (queue + lock)
Thread synchronization:
Because multiple threads of the same process share a piece of storage space, it brings convenience and access conflict. In order to ensure the correctness of data being accessed in the method, the lock mechanism synchronization 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, but there are the following problems
All other threads that need to hold this lock will cause all other objects 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
Thread unsafe cases
1. Ticket buying: there will be oversold, and there may be negative tickets
package syn; //Unsafe ticket buying public class UnsafeByTicket { public static void main(String[] args) { ByTicket station = new ByTicket(); new Thread(station,"I").start(); new Thread(station,"you").start(); new Thread(station,"cattle").start(); } } class ByTicket implements Runnable { //ticket private int ticketNum = 10; boolean flag = true; //External stop @Override public void run() { // Buy a ticket while (flag) { buy(); } } private void buy() { //Judge whether there are tickets if (ticketNum <= 0) { flag = false; return; } // Analog delay try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // Buy a ticket System.out.println(Thread.currentThread().getName() + "Get" + ticketNum--); } } //Operation results // I got 10 // Scalpers get 9 // You got eight // I got seven // Scalpers get 7 // You got six // You get 4 // Scalpers get 5 // I got five // I got three // Cattle get 3 // You got three // Cattle get 2 // I got two // You got 2 // You get 1 // I got - 1 // Cattle get 0
Case 2: withdraw money from the account, and the money withdrawn is greater than the deposit
package syn; //Unsafe withdrawal public class UnsafeBank { public static void main(String[] args) { //account Account account = new Account(100, "fund" ); Drawing you = new Drawing(account, 50, "you"); Drawing griFriend = new Drawing(account, 100, "griFriend"); you.start(); griFriend.start(); } } //account class Account { int money; //balance String name; //full 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 money did you withdraw int drawingMoney; //s balance in hand int nowMoney; 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() + "take,The money is not enough"); } //The occurrence of sleep amplification problem try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //Card balance = = balance - get money account.money = account.money - drawingMoney; //Money in hand nowMoney = nowMoney + drawingMoney; System.out.println(account.name + "The balance is: " + account.money); // Thread.currentThread().getName() = this.getName() System.out.println(this.getName() + "Money in hand" + nowMoney); } } // griFriend, there's not enough money // Fund balance: 0 // Fund balance: - 50 // griFriend's money 100 // The money in your hand is 50
Case 3: unsafe collection
package syn; import java.util.ArrayList; import java.util.List; //Thread unsafe collection 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(); } System.out.println(list.size()); } } //Theoretically, there are 10000 pieces of data, and the actual output is 9998
Synchronization method:
The private keyword ensures that data objects can only be accessed by methods, so we only need to propose a set of mechanism for methods, that is, synchronized keyword, which has two uses: synchronized method and synchronized block
Synchronization method: public synchronized void method(int args) {}
The synchronize method controls the access to the "object". Each object corresponds to a lock. Each synchronize method must obtain the lock of the object calling the method before it can be executed. Otherwise, the thread will block. Once the method is executed, it will exclusively change the lock until the method returns, and the lock will not be released until the method returns. The blocked thread can obtain the lock and continue to execute
Defects: synchronizing will affect efficiency, lock too many, and waste resources
Synchronization block: synchronized (Obj) {}
Obj is called a 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 process
- The first thread accesses, locks the synchronization monitor, and executes the code in it
- The second thread accesses and finds that the synchronization monitor is locked and cannot be accessed
- After the first program is accessed, unlock the synchronization monitor
- The second thread accesses, finds that the synchronization monitor has no lock, and then locks the access
Test and buy tickets
package syn; //Unsafe ticket buying public class UnsafeByTicket { public static void main(String[] args) { ByTicket station = new ByTicket(); new Thread(station,"I").start(); new Thread(station,"you").start(); new Thread(station,"cattle").start(); } } class ByTicket implements Runnable { //ticket private int ticketNum = 10; boolean flag = true; //External stop @Override public void run() { // Buy a ticket while (flag) { try { buy(); // Analog delay Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } // In addition, synchronized becomes a synchronization method, and the lock is this private synchronized void buy() throws InterruptedException { //Judge whether there are tickets if (ticketNum <= 0) { flag = false; return; } // Buy a ticket System.out.println(Thread.currentThread().getName() + "Get" + ticketNum--); } } //Operation results // I got 10 // Scalpers get 9 // You got eight // I got seven // Cattle get 6 // You got five // Scalpers get 4 // You got three // I got two // You get 1
Bank case:
package com.hx.vipmodel.controller; //Unsafe withdrawal public class UnsafeBank { public static void main(String[] args) { //account Account account = new Account(100, "fund" ); Drawing you = new Drawing(account, 50, "you"); Drawing griFriend = new Drawing(account, 100, "griFriend"); you.start(); griFriend.start(); } } //account class Account { int money; //balance String name; //full 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 money did you withdraw int drawingMoney; //s balance in hand int nowMoney; public Drawing(Account account, int drawingMoney, String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } //Withdraw money // Suncronized locks this by default @Override public void run() { // The object to be locked is the amount of change and the object to be operated (bank locked, unable to be locked) synchronized (account) { // Judge whether there is money if (account.money - drawingMoney <= 0) { System.out.println(Thread.currentThread().getName() + "take,The money is not enough"); return; } //The occurrence of sleep amplification problem try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //Card balance = = balance - get money account.money = account.money - drawingMoney; //Money in hand nowMoney = nowMoney + drawingMoney; System.out.println(account.name + "The balance is: " + account.money); // Thread.currentThread().getName() = this.getName() System.out.println(this.getName() + "Money in hand" + nowMoney); } } } // output // Fund balance: 50 // The money in your hand is 50 // griFriend, there's not enough money
JUC--CopyOnWriteArrayList
package com.hx.vipmodel.controller; import java.util.concurrent.CopyOnWriteArrayList; //Test JUC security type collection public class TestJUC { public static void main(String[] args) { CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread(() -> { list.add(Thread.currentThread().getName()); }).start(); } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } } //The expected size is 1000 and the actual output is 10000
Deadlock:
In the scenario where multiple threads occupy some shared resources and wait for the resources occupied by other threads to run, resulting in two or more threads waiting for each other to release resources and stop execution, the problem of "deadlock" may occur when a synchronization block has "locks of more than two objects" at the same time.
Deadlock solution:
Four necessary conditions for deadlock generation:
- Mutually exclusive 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 until they are used
- Circular waiting condition: a circular waiting resource relationship between several processes
Breaking any one or more of the above four conditions will avoid deadlock
package com.hx.vipmodel.controller; //Deadlock: multiple threads will hold the resources needed by each other, and the schedule is deadlocked public class DeadLok { public static void main(String[] args) { Makeup m1 = new Makeup(0, "Cinderella"); Makeup m2 = new Makeup(1, "Snow white"); m1.start(); m2.start(); } } //Lipstick class Lipstick{ } //mirror class Mirror { } class Makeup extends Thread { // Only one resource is needed, and only one is guaranteed by static static Lipstick lipstick = new Lipstick(); static Mirror mirror = new Mirror(); int choice; //choice String girName; //People who use cosmetics Makeup(int choice, String girName) { this.choice = choice; this.girName = girName; } @Override public void run() { // Make up try { makeip(); } catch (InterruptedException e) { e.printStackTrace(); } } // Make up, hold each other's resources, but need to get each other's resources private void makeip() throws InterruptedException { if (choice == 0) { synchronized (lipstick) {//Get lipstick lock System.out.println(this.girName + "Get lipstick lock"); Thread.sleep(1000); synchronized (mirror) { //Want to get a mirror in a second System.out.println(this.girName + "Get the lock of the mirror"); } } } else { synchronized (mirror) {//Get the lock of the mirror System.out.println(this.girName + "Get the lock of the mirror"); Thread.sleep(2000); synchronized (lipstick) {//Want to get lipstick in a second System.out.println(this.girName+"Get the lock of the mirror"); } } } } } //output //Cinderella gets the lock of lipstick //Snow White gets the lock of the mirror //m1 gets the lipstick first, m2 gets the mirror, holds each other's desired resources, and deadlocks each other. The program will not end // Each other's resources, but they need each other's resources // private void makeip() throws InterruptedException { // if (choice == 0) { // synchronized (lipstick) {/ / get the lock of lipstick // System.out.println(this.girName + "lock to get lipstick"); // Thread.sleep(1000); // } // synchronized (mirror) {/ / want to get the mirror in one second // System.out.println(this.girName + "get the lock of the mirror"); // } // } else { // synchronized (mirror) {/ / get the lock of the mirror // System.out.println(this.girName + "get the lock of the mirror"); // Thread.sleep(2000); // } // synchronized (lipstick) {/ / want to get lipstick in one second // System.out.println(this.girName + "get the lock of the mirror"); // // } // } // } //m1 gets lipstick first and m2 gets the mirror. After modification, the other party is not allowed to hold the other party's desired resources. The deadlock problem is solved after synchronized is raised //output // Snow White gets the lock of the mirror // Cinderella gets the lock of lipstick // Cinderella gets the lock of the mirror // Snow White gets the lock of the mirror
Lock lock:
Starting from JDK 5.0, Java provides a more powerful thread synchronization mechanism - synchronization is achieved 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. 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 thread safety control, which can explicitly add and release locks.
Comparison between synchronize and lock
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 time lock
Using Lock lock, the JVM will spend less time to schedule threads, with better performance and better scalability (providing more subclasses)
Priority of use
- Lock > sync code block (has entered the method body and allocated corresponding resources) > sync method > (outside the method body)
Test lock lock
package com.hx.vipmodel.controller; import java.util.concurrent.locks.ReentrantLock; //Test lock lock 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 ticketNum = 10; //Define lock lock private final ReentrantLock lock = new ReentrantLock(); @Override public void run() { while (true) { try { lock.lock(); //Lock if (ticketNum > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(ticketNum--); } else { break; } }finally { // Unlock lock.unlock(); } } } } //output //10 //9 //8 //7 //6 //5 //4 //3 //2 //1
Thread collaboration:
Application scenario: producer, consumer
- Assuming that only one top-grade product 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 are no goods in the warehouse, the producer will put the products into the warehouse, otherwise stop production and wait until the products in the warehouse are taken away by consumers
- If there are products in the warehouse, the consumer can take the products away for consumption, otherwise stop consumption and wait until the goods are put in 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
- For producers, they should inform consumers to wait before producing products, and inform consumers to consume immediately after producing products
- For consumers, after consumption, they should inform producers that they have finished consumption and need to produce new products for consumption
- In the problem of production and consumption, synchronized is not enough
- synchronized can prevent concurrent updating of the same shared resource and realize synchronization
- synchronized cannot be used for thread passing (Communication) between different threads
java provides several methods to solve the communication problem between threads
Wait() means that the thread waits until other threads notify it. Unlike sleep, wait() releases the lock
wait(long timeout) specifies the number of milliseconds to wait
notify() wakes up a waiting thread
notifyAll() wakes up all threads calling the wait() method on the same object, and the threads with higher priority are scheduled first
Note: any method of Object class can only be in the synchronization method or synchronization code block, otherwise an exception will be thrown
Solution 1: pipe pass method
Concurrent collaboration mode, "producer / consumer mode" -- > management process method
- Producer: the module responsible for production data (may be method, object, thread, process)
- Consumer: the module responsible for processing data (possibly method, object, thread and process)
- Buffer: consumers cannot directly use the data of producers. There is a buffer between them
The producer puts the produced data into the buffer, and the consumer takes the data from the buffer
package syn; //Test: producer consumer model -- > using buffer solution: pipe process method import java.nio.channels.Channel; //Producer, consumer, product, buffer public class TestTcp { public static void main(String[] args) { SynContainer synContainer = new SynContainer(); new Produtor(synContainer).start(); new Consumer(synContainer).start(); } } //producer class Produtor extends Thread { SynContainer container; public Produtor(SynContainer container) { this.container = container; } //production @Override public void run() { for (int i = 0; i < 100; i++) { container.push(new Chicken(i)); System.out.println("Produced" + i + "Chicken"); } } } //consumer class Consumer extends Thread { SynContainer container; public Consumer(SynContainer container) { this.container = container; } // x consumer @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("Consumption"+container.pop().id+"Chicken"); } } } ///Products class Chicken { int id; //number public Chicken(int id) { this.id = id; } } //buffer class SynContainer { //Container size Chicken[] chickens = new Chicken[10]; //Counting container int count = 0; // Producers put in products public synchronized void push(Chicken chicken) { //If the container is full, consumers need to consume it if (count == chickens.length) { //Production waiting try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // If it is not full, you 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 to consume if (count == 0) { //Wait for producers to produce and consumers to wait try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //If you can consume count--; Chicken chicken = chickens[count]; //Inform the producer of production after consumption this.notifyAll(); return chicken; } }
Solution 2:
Concurrent collaboration model: "producer / consumer" -- > signal lamp method
Judge a flag bit. If it is true, let it wait. If it is equal to false, let it notify another person. Like a traffic light, "red light stops, green light goes" to judge when the thread listens and wakes up
package syn; //Test producer consumer problem 2: signal lamp method, flag bit solution 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 < 20; i++) { if (i % 2 == 0) { this.tv.play("Playing:A dog's way home"); } else { this.tv.play("Playing:US troops withdraw from Afghanistan"); } } } } //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 actors performed and the audience waited // The audience watched and the actors waited String voice; //A performance boolean flag = true; //t actors perform, f actors wait //perform public synchronized void play(String voice) { if (!flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("The actors performed:" + voice); //After the performance, 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; } }
Thread pool:
Background: resources that are often created and destroyed and used heavily, such as threads in concurrency, have a great impact on performance.
Idea: create many threads in advance, put them into the thread pool, get them directly when using them, and put them back into the pool after using them. It can avoid frequent creation, destruction and reuse. Similar vehicles in public life.
Benefits:
Improved response speed (reduced time to create new threads)
Reduce resource consumption (reuse threads in the thread pool, not creating them every time)
Easy thread management
- corePoolSize: the size of the core pool
- maximumPoolSize: maximum number of threads
- keepAliveTime: when the thread has no task, how long will it last at most and then terminate
JDK 5.0 provides thread pool related APIs: executorservice and Executors
ExecutorService: the real thread pool interface. Common subclass ThreadPoolExecutor
- void execute(Runnable command): executes a task / command without a return value. It is generally used to execute Runnable
- <T> Future < T > submit (Callable < T > task): when a task is executed, there is a return value. Generally, Callable is executed again
- void shutdown(): closes the connection pool
Executors: tool class and factory class of thread pool, which are used to create and return different types of thread pools
package syn; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //Test thread pool public class TestPool { public static void main(String[] args) { // 1. Create service and thread pool // 2. Set the thread pool size newFixedThreadPool ExecutorService service = Executors.newFixedThreadPool(10); // implement service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); // Close connection service.shutdown(); } } class MyThread implements Runnable { @Override public void run() { // for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() ); // } } }
Ways to implement multithreading:
package syn; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; //Review the creation of all thread pools public class AllThread { public static void main(String[] args) { new MyThread1().start(); new Thread(new MyThread2()).start(); FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3()); new Thread(futureTask).start(); try { Integer integer = futureTask.get(); System.err.println(integer); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } //1. Inherit Thread class MyThread1 extends Thread { @Override public void run() { System.out.println("extends Thread "); } } //Implement Runnable interface class MyThread2 implements Runnable { @Override public void run() { System.out.println("implements Runnable"); } } //Implement Callable interface class MyThread3 implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("implements Callable"); return 100; } }