preface
Ten thousand words briefly summarize the multithreading in the process of Java learning. If there are deficiencies, please correct them. If you think they are good, you can also connect them three times
Thread class
-
Inherit Thread class
- Declare a class as a subclass of a Thread. The subclass overrides the method Thread of the run class, and then allocate and start the instance of the subclass
- Custom Thread class inherits Thread class
- Rewrite the run () method and write the thread execution body
- Create a thread object and call the start () method to start the thread
-
Thread creation method 1: inherit the thread class, rewrite the run () method, and call start to start the thread
-
Note: thread startup is not necessarily executed immediately, but is scheduled by CPU
-
summary
- The subclass inherits the Thread class and has the ability of multithreading
- Start thread: subclass object start()
- Not recommended to avoid the limitation of OOP single inheritance
public class TestThread1 extends Thread{ public void run(){ //run method thread body for(int i = 0;i < 200; i++){ System.out.println("I'm looking at the code---"+i); } } public static void main(String[] args) { //main thread //Create a thread object TestThread1 testThread1 = new TestThread1(); //The thread start() method is called testThread1.start(); for(int i = 0;i < 1000;i++){ System.out.println("I am reading a book---"+i); } } }
Picture download
- Realize multi-threaded synchronous downloading of pictures
public class TestThread extends Thread{ private String url;//Network picture address private String name;//Saved file name public TestThread(String url,String name){ this.url = url; this.name = name; } //The execution body of the image download thread public void run(){ WebDownloader webDownloader = new WebDownloader(); webDownloader.downloader(url,name); System.out.println("Downloaded the file named:"+name); } public static void main(String[] args) { TestThread t1 = new TestThread("","1.jpg"); TestThread t2 = new TestThread("","2.jpg"); TestThread t3 = new TestThread("","3.jpg"); t1.start(); t2.start(); t3.start(); } } //Downloader class WebDownloader{ //Download method public void downloader(String url,String name){ try { FileUtils.copyURLToFile((new URL(url)), new File(name)); }catch (IOException e){ e.printStackTrace(); System.out.println("IO Abnormal, Downloader There is a problem with the method“); } } }
Runnable interface
-
Implement the Runable interface: declare the implementation class Runnable interface. That class then implements the run method. You can then assign an instance of the class, pass it as a parameter when creating the Thread, and start it.
-
Create thread mode 2:
- Implement the runable interface
- When rewriting the run method, the execution thread object needs to be thrown into the implementation class of the runnable interface
- Call start()
-
Thread creation mode 2: implement the runnable interface, rewrite the run () method, and throw the execution thread into the thread object
-
summary
-
The implementation interface Runable 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
-
public class TestThread1 implements Runnable{ public void run(){ //run method thread body for(int i = 0;i < 200; i++){ System.out.println("I'm looking at the code---"+i); } } public static void main(String[] args) { //Create the implementation class object of runnable interface TestThread1 testThread1 = new TestThread1(); //Create a thread object and start our thread through the thread object new Thread(testThread1).start(); for(int i = 0;i < 1000;i++){ System.out.println("I am reading a book---"+i); } } }
Picture download
public class TestThread implements Runnable{ private String url;//Network picture address private String name;//Saved file name public TestThread(String url,String name){ this.url = url; this.name = name; } //The execution body of the image download thread public void run(){ WebDownloader webDownloader = new WebDownloader(); webDownloader.downloader(url,name); System.out.println("Downloaded the file named:"+name); } public static void main(String[] args) { TestThread t1 = new TestThread("","1.jpg"); TestThread t2 = new TestThread("","2.jpg"); TestThread t3 = new TestThread("","3.jpg"); new Thread(t1).start(); new Thread(t2).start(); new Thread(t3).start(); } } //Downloader class WebDownloader{ //Download method public void downloader(String url,String name){ try { FileUtils.copyURLToFile((new URL(url)), new File(name)); }catch (IOException e){ e.printStackTrace(); System.out.println("IO Abnormal, Downloader There is a problem with the method“); } } }
Tortoise and rabbit race
//Simulated tortoise rabbit race public class Race implements Runnable { //winner private static String winner; @Override public void run(){ for (int i = 0; i <= 100; i++) { //Simulated rabbit rest if (Thread.currentThread().getName().equals("rabbit") && i % 10 == 0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } //Judge whether the game is over boolean flag = gameover(i); //If the game is over, stop the program if (flag) { break; } System.out.println(Thread.currentThread().getName() + "-->Run away" + i + "step"); } } //Judge whether to complete the game private boolean gameover(int steps) { //Judge whether there is a winner if (winner != null) {//If winner is not null, there is a winner return true; } else { if (steps >= 100) { winner = Thread.currentThread().getName(); System.out.println("Winner is" + winner); return true; } } return false; } public static void main(String[] args) { Race race = new Race(); new Thread(race, "rabbit").start(); new Thread(race, "tortoise").start(); } }
Callable interface
- Thread creation mode 3
- Implement the callable interface
- Benefits of callable
- You can set the return value
- Exceptions can be thrown
- summary
- To implement the Callable interface, the return value type is required
- When overriding the call method, you need to throw an exception
- Create target object
- Create execution service: executorservice ser = executors newFixedThreadPool(3)
- Submit execution: futuresult1 = Ser submit(t1)
- Get result: Boolean R1 = result1 get()
- Shut down the service: Ser shutdownNow()
Picture download
public class TestCallable implements Callable<Boolean> { private String url; //Network picture address private String name; //Saved file name //Constructor -- implementation call public TestCallable(String url, String name) { this.url = url; this.name = name; } //Download the execution body of the picture @Override public Boolean call() { WebDownloader webDownloader = new WebDownloader(); //Incoming method webDownloader.downloader(url, name); System.out.println("The downloaded file name is" + name); return true; } public static void main(String[] args) throws Exception { TestCallable t1 = new TestCallable("http://b-ssl.duitang.com/uploads/item/201704/21/20170421083329_3cxt8.png", "1.png"); TestCallable t2 = new TestCallable("https://i02piccdn.sogoucdn.com/7e1dad42a62db2df", "2.png"); TestCallable t3 = new TestCallable("https://i01piccdn.sogoucdn.com/f13b319fd77655ec", "3.png"); //Create execution service: ExecutorService ser = Executors.newFixedThreadPool(3); //Submit for execution: Future<Boolean> r1 = ser.submit(t1); Future<Boolean> r2 = ser.submit(t2); Future<Boolean> r3 = ser.submit(t3); //Get results: boolean rs1 = r1.get(); boolean rs2 = r2.get(); boolean rs3 = r3.get(); //Shut down service: ser.shutdownNow(); } } //Downloader class WebDownloader { //Download - Method public void downloader(String url, String name) { try { FileUtils.copyURLToFile(new URL(url), new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("IO Abnormal, down There is a problem with your method!"); } } }
Static proxy mode
-
concept
- Both real objects and proxy objects need to implement an interface
- The proxy object should represent the real role
-
benefit
- Proxy objects can do many things that real objects cannot do
- Real objects focus on doing their own things
public class StaticProxy { public static void main(String[] args) { You you=new You(); WeddingCompany weddingCompany=new WeddingCompany(you); //Equivalent to new WeedingCompany (new you()) weddingCompany.HappyMarry(); } } //Functional interface interface Marry{ void HappyMarry(); } //Implement Mary's interface //Real role class You implements Marry{ @Override public void HappyMarry() { System.out.println("Are you getting married?,Looks super happy"); } } //Implement Mary's interface //Acting role - wedding company class WeddingCompany implements Marry{ //Proxy real object private Marry target; //Construction method public WeddingCompany(Marry target){ this.target=target; } @Override public void HappyMarry() { before(); this.target.HappyMarry();//This is the real object after(); } private void before(){ System.out.println("Before marriage, set up the scene"); } private void after(){ System.out.println("After marriage, the final payment"); } }
Lamda expression
- λ The eleventh letter in the Greek alphabet. Its English name is Lambda
- Avoid too many anonymous internal definitions
- Its essence belongs to the concept of functional programming
- (params) - > exosession [expression]
- (params) - > statement [expression]
- (params) - > [expression]
- a->System.out.println("I Like lamdbda2");
- Definition of Functional Interface
- Any interface that contains only one abstract method is a functional interface
public interface Runnable{ public abstract void run(); }
- For functional interfaces, we can create the interface object through lamdba expression
- Example 1
//Derivation of Lambda expression public class TestLambda01 { //Add static (3. Static required) static class Like2 implements ILike { @Override public void lambda() { System.out.println("I Like lamdbda2"); } } //After defining the interface and implementation class (implementation interface), write the main method public static void main(String[] args) { //Functional interface name + user defined variable = new + implementation class (implementation interface) variable Like ILike like=new Like(); like.lambda(); //Static inner class //Custom variable name = new + implementation class (implementation interface) variable Like2 like=new Like2(); like.lambda(); //4. Local internal class class Like3 implements ILike { @Override public void lambda() { System.out.println("I Like lamdbda3"); } } like=new Like3(); like.lambda(); //5. Anonymous inner class. There is no class name. You must use the interface or parent class like = new ILike() { @Override public void lambda() { System.out.println("I Like lamdbda4"); } }; like.lambda(); //6. Simplify connection with lambda like=()-> { System.out.println("I Like lamdbda5"); }; like.lambda(); } } //1. Define a functional interface interface ILike{ void lambda(); } //2. Implementation class (implementation interface) //implements class Like implements ILike { @Override public void lambda() { System.out.println("I Like lamdbda1"); } }
- Example 2
public class TestLambda02 { public static void main(String[] args) { ILove love=null; //1.lambda simplification /* ILove love=(int a)->{ System.out.println("I Love You-->"+a); }; //Simplify 1 Parameter type love=(a)->{ System.out.println("I Love You-->"+a); };*/ //Simplification 2 Simplified parentheses love=(a,b)->{ System.out.println("I Love You-->"+a+"-->"+b); }; love.love(521,520); //Simplify 3 Remove curly braces love=(a,b)-> System.out.println("I Love You-->"+a+"-->"+b); love.love(521,520); } } //Functional interface interface ILove{ void love(int a,int b); }
- summary
- lambda expressions can only be reduced to one line if they have only one line of code
- If there are multiple lines, wrap them in code blocks (i.e. curly braces)
- The premise is that the interface must be functional (only one method)
- Parameter types can also be removed from multiple parameters. If you want to remove them, you must remove them all and add parentheses (a,b)
Thread state
Thread method
method | explain |
---|---|
setPriority(int newPriority) | Change the priority of a thread |
static void sleep(long millis) | Hibernates the currently executing thread for the specified number of milliseconds |
void join() | Wait for the thread to terminate |
static void yield | Pauses the currently executing thread object and executes other threads |
void interrupt() | Interrupt the thread. Don't do it this way |
boolean isAlive() | Test whether the thread is active |
Thread stop
- It is recommended that the thread stop normally - > utilization times, and dead loop is not recommended
- It is recommended to use flag bit - > set a flag
- 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 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 stop the thread testStop.stop(); System.out.println("Thread has reached 900, stop"); } } } }
Thread sleep
- sleep (time) specifies the number of milliseconds that the current thread is blocked (1000ms=1s)
- Exception InterruptedException in sleep
- When the sleep time arrives, the thread enters the ready state
- sleep can simulate network delay, countdown, etc
- Every object has a lock, and sleep will not release the lock
- Analog network delay: the occurrence of amplification problems
public class TestSleep 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) { TestSleep ticket=new TestSleep(); //Random output new Thread(ticket,"Xiao Ming").start(); new Thread(ticket,"teacher").start(); new Thread(ticket,"Scalpers").start(); } }
- Realize the countdown and obtain the system time
//Analog countdown public class TestSleep02 { public static void main(String[] args) { //Analog countdown //tenDown(); //Print current system time Date startTime = new Date(System.currentTimeMillis());//Get the current time of the system while (true){ try { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime)); startTime = new Date(System.currentTimeMillis());//Update current system time } catch (InterruptedException e) { e.printStackTrace(); } } } public static void tenDown(){ int num=10; while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(num--); if(num<=0) { break; } } } }
Thread yield
- Comity thread: pause the currently executing thread without blocking it
- Change the thread from running state to ready state
- Let the CPU readjust, comity is not necessarily successful! Look at CPU mood
//Test comity thread public class TestYield { public static void main(String[] args) { MyYield myYield=new MyYield(); //Start thread new Thread(myYield,"a").start(); new Thread(myYield,"b").start(); } } //A thread class is required class MyYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"Thread start execution"); Thread.yield();//Thread comity System.out.println(Thread.currentThread().getName()+"Thread stop execution"); } }
Thread join
- Join merge threads. After this thread is successfully executed, execute other threads. Other threads are blocked (you can imagine jumping in line)
//Test Join public class TestJoin implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("vip The VIP is coming. Please make way!"+i); } } public static void main(String[] args) { //Start thread TestJoin testJoin=new TestJoin(); Thread thread=new Thread(testJoin); thread.start(); //Main thread for (int i = 0; i < 1000; i++) { if(i==200){ try { thread.join();//Jump in line } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("main"+i); } } }
Thread state
- A thread can be in one of the following states
- NEW
Threads that have not been started are in this state. - RUNNABLE
The thread executing in the Java virtual machine is in this state. - BLOCKED
Threads that are blocked waiting for a monitor lock are in this state. - WAITING
A thread that is waiting for another thread to perform a specific action is in this state. - TIMED_WAITING
The thread that is waiting for another thread to perform the action for the specified waiting time is in this state. - TERMINATED
The exited thread is in this state.
- NEW
- A thread can be in a state at a given point in time. These states are virtual machine states that do not reflect the state of any operating system thread.
//Observe the status of the test thread public class TestState { public static void main(String[] args) { Thread thread=new Thread(()->{ for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("123123"); }); //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 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } state= thread.getState();//Update thread status System.out.println(state);//Output status } } }
thread priority
- Java provides a thread scheduler to monitor all threads that enter the ready state after startup. The thread scheduler determines which thread should be scheduled to execute according to priority
- The priority of threads is expressed in numbers, ranging from 1 to 10
- Thread.MIN_PRIORITY=1
- Thread.MAX_PRIORITY=10
- Thread.NORM_PRIORITY=5
- Change or obtain priorities in the following ways
- getPriority
- setPriority(int xxx)
- Priority setting is recommended before start() scheduling
- Low priority only means that the probability of obtaining scheduling is low, not that it will not be called if the priority is low, which depends on the scheduling of CPU (performance inversion)
daemon thread
- Threads are divided into user threads and daemon threads
- setDaemon has only two values true/false
- The default value is false, which means user threads. Normal threads are user threads
- The virtual machine must ensure that the user thread has completed execution
- The virtual machine does not have to wait for the daemon thread to finish executing
- Example: record operation logs in the background, monitor memory, garbage collection, etc
//Test daemon thread 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); //Start daemon thread thread.start(); new Thread(you).start();//User thread start } } //Daemon thread class God implements Runnable{ @Override public void run() { while(true) { System.out.println("Buddha bless you!"); } } } //User thread class You 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!======="); } }
Thread synchronization
Thread synchronization mechanism
-
Concurrency: the same object is operated by multiple threads at the same time
-
When dealing with multithreading, when multiple threads access the same object and some threads want to modify the object, we need thread synchronization. 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
-
Conditions for thread synchronization: queue + lock
-
Defects in thread synchronization
- Since 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 access in the method, a lock mechanism is added during access
- When a thread obtains the exclusive lock of an object and monopolizes resources, other threads must wait and release the lock after use
- Thread synchronization has the following problems
- Holding a lock by one thread will cause all other threads that need the lock to hang
- When multiple threads compete, 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
Three unsafe cases
- Case 1
//Unsafe ticket purchase //Thread unsafe, with 0 and negative output public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket station=new BuyTicket(); new Thread( station,"Huahua 001").start(); new Thread( station,"Huahua 002").start(); new Thread( station,"Huahua 003").start(); } } //Need a ticket purchasing method (a multi thread) class BuyTicket implements Runnable{ //Number of votes required private int ticketNums=10; boolean flag=true;//External stop mode @Override public void run() { while (flag){ buy(); } } //Create ticket buying method private void buy(){ //Judge whether there are tickets if (ticketNums<=0) { flag=false; return; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //Buy a ticket System.out.println(Thread.currentThread().getName()+"Get"+ticketNums--); } }
- Case 2
//Unsafe withdrawal //Need two people to withdraw money from the bank -- > need an account public class UnsafeBank { public static void main(String[] args) { //account Account account=new Account(100,"Marriage funds"); Drawing you=new Drawing(account,50,"you"); Drawing yougirlfriend=new Drawing(account,100,"yougirlfriend"); you.start(); yougirlfriend.start(); } } //account class Account{ int money;//balance String name;//Card number 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; //Cash in hand public Drawing(Account account, int drawingMoney,String name){ super(name); this.account=account; this.drawingMoney=drawingMoney; } @Override //Withdraw money public void run() { if(account.money-drawingMoney<0){//Judge whether the account has balance System.out.println(Thread.currentThread().getName()+"Sorry, your credit is running low!"); return; } try { Thread.sleep(1000); //The occurrence of sleep amplification problem } catch (InterruptedException e) { e.printStackTrace(); } account.money= account.money-drawingMoney;//Card balance = balance - the money you withdraw nowMoney=nowMoney+drawingMoney; //The money in your hand System.out.println(Thread.currentThread().getName()+"Money in hand:"+nowMoney); System.out.println(account.name+"The balance is:"+account.money); //Here is this Getname () is equivalent to thread currentThread(). getName() } }
- Case 3
//Thread unsafe collection public class UnsafeList { public static void main(String[] args) { List<String> list=new ArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } }
Synchronization method and synchronization block
Synchronization method
- 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 synchronizeed void method(int args){}
- The synchronized method controls access to "objects", and each object corresponds to a lock
- Each synchronized method must obtain the lock of the object calling the method before it can be executed. Otherwise, the thread will block. Once the method is executed, it will monopolize the lock and release the lock until the method returns. The blocked thread can obtain the lock and continue to execute
- Defect: declaring a large method synchronized will affect efficiency
Synchronization block
-
synchronized(Obj){}
-
Obj calls it 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 thread is accessed, unlock the synchronization monitor
-
The second thread accesses, finds that the synchronization monitor has no lock, and then locks and accesses
-
-
Using synchronization to solve three unsafe cases
-
Case 1
//Unsafe ticket purchase //Thread unsafe, with 0 and negative output public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket station=new BuyTicket(); new Thread( station,"Huahua 001").start(); new Thread( station,"Huahua 002").start(); new Thread( station,"Huahua 003").start(); } } //Need a ticket purchasing method (a multi thread) class BuyTicket implements Runnable{ //Number of votes required private int ticketNums=10; boolean flag=true;//External stop mode @Override public void run() { while (flag){ buy(); } } //Create ticket buying method //The synchronized synchronization method locks this (BuyTicket) private synchronized void buy(){ //Judge whether there are tickets if (ticketNums<=0) { flag=false; return; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //Buy a ticket System.out.println(Thread.currentThread().getName()+"Get"+ticketNums--); } }
- Case 2
//Unsafe withdrawal //Need two people to withdraw money from the bank -- > need an account public class UnsafeBank { public static void main(String[] args) { //account Account account=new Account(100,"Marriage funds"); Drawing you=new Drawing(account,50,"you"); Drawing yougirlfriend=new Drawing(account,100,"yougirlfriend"); you.start(); yougirlfriend.start(); } } //account class Account{ int money;//balance String name;//Card number 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; //Cash in hand public Drawing(Account account, int drawingMoney,String name){ super(name); this.account=account; this.drawingMoney=drawingMoney; } @Override //Withdraw money // synchronized the default lock is this //The object of the lock is the amount of change, that is, the amount that needs to be added, deleted and modified public void run() { synchronized(account){ if(account.money-drawingMoney<0){//Judge whether the account has balance System.out.println(Thread.currentThread().getName()+"Unable to withdraw money, insufficient balance!"); return; } try { Thread.sleep(1000); //The occurrence of sleep amplification problem } catch (InterruptedException e) { e.printStackTrace(); } account.money= account.money-drawingMoney;//Card balance = balance - the money you withdraw nowMoney=nowMoney+drawingMoney; //The money in your hand System.out.println(Thread.currentThread().getName()+"Money in hand:"+nowMoney); System.out.println(account.name+"The balance is:"+account.money); //Here is this Getname () is equivalent to thread currentThread(). getName() } } }
- Case 3
//Thread unsafe collection public class UnsafeList { public static void main(String[] args) { List<String> list=new ArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ synchronized (list){ list.add(Thread.currentThread().getName()); } }).start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } }
CopyOnWriteArrayList
//Test the collection of JUC security types public class TestJUC { public static void main(String[] args) { CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } 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
package thread; //Deadlock, multiple threads hold each other's required resources, and then form a deadlock public class DeadLock { public static void main(String[] args) { Makeup g1=new Makeup(0,"Grey Gu Liang"); Makeup g2=new Makeup(1,"Bai Guliang"); g1.start(); g2.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 lipstic=new Lipstick(); static Mirror mirror=new Mirror(); int choice; //choice String girlname;//People who use cosmetics //Using constructors Makeup(int choice,String girlname){ this.choice=choice; this.girlname=girlname; } //To inherit the Thread type, you need to override the run method @Override public void run() { try { makeup(); } catch (Exception e) { e.printStackTrace(); } //Make up } //Make up, hold each other's locks, and need to get each other's resources private void makeup(){ if(choice==0) { synchronized (lipstic){//Get lipstick lock System.out.println(this.girlname+"Get lipstick lock"); try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } //The way to solve the deadlock is to take the synchronized (mirror) below out of the if statement synchronized (mirror){//I want to get the mirror in a second System.out.println(this.girlname+"Get the lock of the mirror"); } }else{ synchronized (mirror) {//Get the lock of the mirror System.out.println(this.girlname + "Get the lock of the mirror"); try { Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } } //The way to solve the deadlock is to take the synchronized (lipstic) below out of the else statement synchronized (lipstic) {//Want to get lipstick in a second System.out.println(this.girlname + "Get lipstick lock"); } } } }
- 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
- Cyclic waiting condition: a cyclic waiting resource relationship is formed between several processes
- The four necessary conditions for deadlock are listed above. We can avoid deadlock as long as we try to break any one or more of them
LocK lock
- From jdk5 Since 0, Java has provided a more powerful thread synchronization mechanism - synchronization is achieved by explicitly defining the synchronization Lock object, which uses the Lock object as the
- 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 class implements Lock. It has the same concurrency and memory semantics as synchronized. ReentrantLock is commonly used in thread safety control. It can explicitly add and release locks
- format
//grammar class A{ private final ReentrantLock lock=new ReentrantLock(); public void mainone(){ try{ lock.lock(); //Thread safe code }finally { lock.unlock(); //If the finally synchronization code has an exception, write unlock () to the statement block } } }
- case
//Test 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 ticketNums=10; //Define Lock lock (reentrant Lock) private final ReentrantLock lock =new ReentrantLock(); @Override public void run() { while(true) { try{ lock.lock();//Lock if(ticketNums>0){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(ticketNums--); }else{ break; } }finally{ //Unlock lock.unlock(); } } } }
- synchronized vs Lock
- Lock is an explicit lock (manually open and close the lock, don't forget to close the lock), and synchronized is an implicit lock, which is automatically released out of the scope
- Lock only has code block lock, and synchronized has code block lock and method lock
- Using Lock lock, the JVM will spend less time scheduling threads, with better performance and better scalability (providing more subclasses)
- Priority: Lock > sync code block > sync method
Thread collaboration
Thread communication
Method name | effect |
---|---|
wait() | Different from other threads, sleep means that the lock will be released all the time |
wait(long timeout) | Specifies the number of milliseconds to wait |
notify() | Wake up a waiting thread |
notifyAll() | Wake up all threads calling the wait() method on the same object, and the threads with high priority are scheduled first |
- All methods of Object class can only be used in synchronization methods or synchronization code blocks, otherwise different iiiegamonitorstateexception will be thrown
producer consumer problem
- Pipe program method
//Producer consumer product buffer 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 required @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("Produced"+i+"Chicken"); container.push(new Chicken(i)); } } } //consumer class Consumer extends Thread{ SynContainer container; public Consumer(SynContainer container){ this.container=container; } //consumption @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("Consumption--->"+container.pop().id+"Chicken"); } } } //product class Chicken{ int id;//Product number is required //Construction method alt+insert public Chicken(int id) { this.id = id; } } //buffer class SynContainer { //A container size is required Chicken[] chickens = new Chicken[10]; int count = 0;//Container counter //Producers put in products (synchronized to achieve synchronization) public synchronized void push(Chicken chicken) { //If the container is full, it needs to wait for consumers to consume if (count == chickens.length) { //This is the need to inform consumers, production waiting try{ this.wait(); }catch (InterruptedException e){ e.printStackTrace(); } } //If it is not full, we need to put 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 producers to produce and consumers to wait try{ this.wait(); }catch (InterruptedException e){ e.printStackTrace(); } } //If you can consume count--; Chicken chicken = chickens[count]; //After eating, inform the producer to produce this.notifyAll(); return chicken; } }
- Signal lamp method
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){ //Construction method this.tv=tv; } @Override public void run() { for (int i = 0; i < 20; i++) { if(i%2==0){ this.tv.play("Happy camp playing"); }else{ this.tv.play("Jitter: tiktok: record the good life"); } } } } //Consumer -- > audience class Watcher extends Thread{ TV tv; public Watcher(TV tv){ //Construction method 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 //Audience watching, actors waiting for False String voice;//A performance boolean flag=true;//Set the flag bit to judge whether the actor performs //perform public synchronized void play(String voice){ if(!flag){ //If the audience is watching, the actor needs to wait for this wait(); 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){ //If the actor is performing. The audience needs to wait for this wait(); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("The audience watched:"+voice); //Inform the actors of the performance after the audience has watched 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 and destruction and realize reuse. Similar to public transport in life
-
benefit
-
Improved response speed (reduced time to create new threads)
-
Reduce resource consumption (reuse threads in the thread pool and do not need to be created every time)
-
Easy thread management (...)
- corePoolSize: the size of the core pool
- maximumPoolSize: maximum number of threads
- keepAliveTime: when a thread has no task, how long does it last at most and then it will terminate
-
-
a key
-
JDK5. Thread pool related API s: ExecutorService and Executors have been provided since 0
-
ExecutorService: the real thread pool interface. Common subclass ThreadPoolExcutor
-
Runnable: no command, runnable: no command to execute
-
Future submit(Callable ask): when a task is executed and there is a return value, it is generally executed again
-
void shutdown(): closes the connection pool
-
Executors: tool class and factory class of thread pool, which are used to create and return thread pools of different types
-
//Test thread pool public class TestPool { public static void main(String[] args) { //1. Create service and thread pool //The newFixedThreadPool parameter is the size of the thread pool ExecutorService service= Executors.newFixedThreadPool(10); //implement service.execute(new MyTread()); service.execute(new MyTread()); service.execute(new MyTread()); service.execute(new MyTread()); //2. Close the connection pool service.shutdown(); } } class MyTread implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }