Detailed explanation of multithreading
summary
Core concept
- Threads are independent execution paths
- When the program is running, there will be multiple threads in the background, such as main thread and gc thread, even if there is no thread created by itself
- 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 cannot be considered as intervention.
- When operating on the same resource, there will be the 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.
Thread creation
Three creation methods
-
Inherit Thread class
- 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 //Summary: note that thread startup is not necessarily executed immediately, but is scheduled by cpu public class TestThread01 extends Thread{ @Override 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 TestThread01 testThread01 = new TestThread01(); //Call the start method to start the thread testThread01.start(); for (int i = 0; i < 1000; i++) { System.out.println("I'm learning multithreading----"+i); } } }
Network diagram Download
import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; //Practice Thread to realize multi-threaded synchronous downloading of pictures public class TestThread02 extends Thread{ private String url; private String name; public TestThread02(String url,String name){ this.url =url; this.name = name; } //Thread executor for downloading pictures @Override public void run() { WebDownloader webDownloader = new WebDownloader(); webDownloader.Downloader(url,name); System.out.println("Downloaded the file named:"+name); } public static void main(String[] args) { TestThread02 testThread01 = new TestThread02("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F121420113514%2F201214113514-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128667&t=22e223725381f757ce22e2c9464be38d","1.jpg"); TestThread02 testThread02 = new TestThread02("https://img1.baidu.com/it/u=1407750889,3441968730&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=799","2.jpg"); TestThread02 testThread03 = new TestThread02("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp08%2F01042323313046.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128718&t=8cbd7d628ec7bf5b1953c8ac9edaf2ff","3.jpg"); //Open thread testThread01.start(); testThread02.start(); testThread03.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 Method error!"); } } }
Not recommended: avoid the limitation of oop single inheritance
-
Implement Runnable interface
//Multithreading using Runable public class MyRunnable01 implements Runnable{ @Override public void run() { for (int i = 0; i < 200; i++) { System.out.println("run()----"+i); } } public static void main(String[] args) { new Thread(new MyRunnable01()).start(); for (int i = 0; i < 1000; i++) { System.out.println("main()-----"+i); } } }
Network diagram Download
import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; public class MyRunnable02 implements Runnable{ private String url; private String name; public MyRunnable02(String url,String name){ this.url =url; this.name = name; } //Thread executor for downloading pictures @Override public void run() { WebDownloader webDownloader = new WebDownloader(); webDownloader.Downloader(url,name); System.out.println("Downloaded the file named:"+name); } public static void main(String[] args) { MyRunnable02 mr01 = new MyRunnable02("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F121420113514%2F201214113514-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128667&t=22e223725381f757ce22e2c9464be38d","1.jpg"); MyRunnable02 mr02 = new MyRunnable02("https://img1.baidu.com/it/u=1407750889,3441968730&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=799","2.jpg"); MyRunnable02 mr03 = new MyRunnable02("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp08%2F01042323313046.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128718&t=8cbd7d628ec7bf5b1953c8ac9edaf2ff","3.jpg"); //Open thread new Thread(mr01).start(); new Thread(mr02).start(); new Thread(mr03).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
//A resource StartThread4 station = new StartThread4(); //Multiple agents new Thread(station,"Xiao Ming").start(); new Thread(station,"Xiao Hong").start(); new Thread(station,"teacher").start();
//Multiple threads operate on the same object at the same time //Simulated ticket grabbing //Problems found: when multiple threads operate on the same resource, the thread is unsafe and the data is disordered public class MyRunnable03 implements Runnable{ //Initial 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-- + "Tickets."); } } public static void main(String[] args) { MyRunnable03 myRunnable03 = new MyRunnable03(); new Thread(myRunnable03,"Xiao Ming").start(); new Thread(myRunnable03,"teacher").start(); new Thread(myRunnable03,"Scalpers").start(); } }
-
Implement Callable interface
1. To implement the Callable interface, the return value type is required
2. When rewriting the call method, you need to throw an exception
3. Create target object
4. Create execution service: executorservice ser = executors newFixedThreadPool(1);
5. Submit execution: future result1 = Ser submit(t1);
6. Get the result: Boolean R1 = result1 get()
7. Close the service: Ser shutdownNow();
import com.sun.org.apache.xpath.internal.operations.Bool; import java.util.concurrent.*; //Thread creation method 3: implement Callable interface /* callable Benefits of 1.Can have return value 2.Throw exception */ public class MyCallableDemo01 implements Callable<Boolean> { private String url; private String name; public MyCallableDemo01(String url,String name){ this.url =url; this.name = name; } //Thread executor for downloading pictures @Override public Boolean call() { WebDownloader webDownloader = new WebDownloader(); webDownloader.Downloader(url,name); System.out.println("Downloaded the file named:"+name); return true; } public static void main(String[] args) throws ExecutionException, InterruptedException { MyCallableDemo01 md01 = new MyCallableDemo01("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F1114%2F121420113514%2F201214113514-1-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128667&t=22e223725381f757ce22e2c9464be38d","1.jpg"); MyCallableDemo01 md02 = new MyCallableDemo01("https://img1.baidu.com/it/u=1407750889,3441968730&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=799","2.jpg"); MyCallableDemo01 md03 = new MyCallableDemo01("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp08%2F01042323313046.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648128718&t=8cbd7d628ec7bf5b1953c8ac9edaf2ff","3.jpg"); //Execute service creation ExecutorService ser = Executors.newFixedThreadPool(3); //Submit for execution Future<Boolean> result1 = ser.submit(md01); Future<Boolean> result2 = ser.submit(md02); Future<Boolean> result3 = ser.submit(md03); //Get results boolean r1 = result1.get(); boolean r2 = result2.get(); boolean r3 = result3.get(); //Shut down service ser.shutdown(); } }
Case: Tortoise rabbit race
//Tortoise and rabbit race public class Race implements Runnable{ //winner private static String winner; @Override public void run() { for (int i = 0; i <= 100; i++) { //Judge whether the game is over boolean flag = gameOver(i); if (flag){//The game is over, stop the game break; } //Rabbit sleep // if (Thread.currentThread().getName().equals("rabbit") & & I% 10 = = 0){ // try { // Thread.sleep(1); // } catch (InterruptedException e) { // e.printStackTrace(); // } // } System.out.println(Thread.currentThread().getName() + "-->Run away" + i + "step"); } } //Determine whether the game is over private boolean gameOver(int steps){ if (steps>=100){ winner = Thread.currentThread().getName(); System.out.println("winner is" + winner); return true; } if (winner!=null){//There are already winners return true; } return false; } public static void main(String[] args) { Race race = new Race(); new Thread(race,"rabbit").start(); new Thread(race,"tortoise").start(); } }
Static proxy
package proxystatic; //Static proxy public class StaticProxy { public static void main(String[] args) { new Wedding(new You()).HappyMarry(); } } interface Marry{ void HappyMarry(); } //Real character, you get married class You implements Marry{ @Override public void HappyMarry() { System.out.println("I'm married, very happy!"); } } //Acting role to help you get married class Wedding implements Marry{ private Marry target; public Wedding(Marry target) { this.target = target; } @Override public void HappyMarry() { before(); this.target.HappyMarry(); after(); } private void after() { System.out.println("After marriage, you need the final payment"); } private void before(){ System.out.println("Before marriage, you need to decorate the scene"); } }
Lamda expression
-
Avoid too many anonymous inner class definitions
-
Its essence belongs to the concept of functional programming
(params) -> expression[expression] (params) -> statement[sentence] (params) -> {statements}
a-> System.out.println("i like lambda-->"+a)
``new Thread(()->System. out. Println ("multi thread learning...) start();`
-
Definition of functional interface: any interface is a functional interface if it contains only one abstract method. Functional interfaces can create objects of the interface through lambda expressions.
package lambdaShow; public class TestLambda01{ //3. Static internal class static class Like2 implements ILike{ @Override public void lambda() { System.out.println("I like lambda2"); } } public static void main(String[] args) { ILike like = new Like(); like.lambda(); like = new Like2(); like.lambda(); //4. Local internal class class Like3 implements ILike{ @Override public void lambda() { System.out.println("I like lambda3"); } } like = new Like3(); like.lambda(); //5. Anonymous inner class like = new ILike() { @Override public void lambda() { System.out.println("I like lambda4"); } }; like.lambda(); //6.lambda expression like = () -> { System.out.println("I like lambda5"); }; like.lambda(); } } //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"); } }
package lambdaShow; //Summary: lambda expressions can be simplified into one line only when there is one line of code. If there are multiple lines, wrap them with code blocks. //The premise is that the interface is functional //You can also remove parameter types from multiple parameters. To remove all parameters, parentheses must be added public class TestLambda02 implements ILove{ @Override public void Love(int hours) { System.out.println("I love you--" + hours); } public static void main(String[] args) { ILove love = null; love = (int hours) -> { System.out.println("I love you,too ---" + hours); }; //1. The first simplified omitting parameter love = (hours)->{ System.out.println("I love you,too ---" + hours); }; //2. The second simplification omits parentheses love = hours->{ System.out.println("I love you,too ---" + hours); }; //3. The third simplification omits curly braces love = hours-> System.out.println("I love you,too ---" + hours); love.Love(5201314); } } interface ILove{ void Love(int hours); }
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
- The stop()\destroy() method provided by JDK is not recommended. (abandoned)
- It is recommended that the thread stop by itself
- It is recommended to use a flag bit to terminate. If the variable flag=false, the thread will be terminated.
public class TestStop01 implements Runnable{ //Set a flag bit private boolean flag = true; @Override public void run() { int i = 0; while (flag){ System.out.println("run. . . . Runnable" + i++); } } //Set an open method to stop the thread and convert the flag bit public void stop(){ this.flag = false; } public static void main(String[] args) { TestStop01 testStop01 = new TestStop01(); new Thread(testStop01).start(); for (int i = 0; i < 1000; i++) { if (i==900){ //Call the stop method to stop the thread testStop01.stop(); System.out.println("The thread stopped"); } System.out.println("main--" + i); } } }
-
Thread sleep
- Sleep specifies the number of milliseconds the current thread is blocking
- 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.
import java.text.SimpleDateFormat; import java.util.Date; public class TestSleep01 { public static void main(String[] args) throws InterruptedException { timeDown(); Date startTime = new Date(System.currentTimeMillis());//Get current system time while (true){ Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH-mm-ss").format(startTime)); startTime = new Date(System.currentTimeMillis());//Get current system time } } public static void timeDown() throws InterruptedException { int time = 10; while (true){ Thread.sleep(1000); System.out.println(time--); if (time<=0){ break; } } } }
-
Thread comity
- Comity thread: pause the currently executing thread without blocking it
- Change the thread from running state to ready state
- Let the cpu reschedule, comity is not necessarily successful! Look at your mood
public class TestYield01 { 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() + "The thread starts executing"); Thread.yield();//Thread comity System.out.println(Thread.currentThread().getName() + "Thread stop execution"); }
-
Join
- Join merge threads. After this thread completes execution, execute other threads. Other threads are blocked
- Imagine jumping in line
public class TestJoin implements Runnable{ @Override public void run() { for (int i = 0; i < 500; i++) { System.out.println("Threaded VIP coming" + i); } } public static void main(String[] args) throws InterruptedException { TestJoin testJoin = new TestJoin(); Thread thread = new Thread(testJoin); thread.start(); for (int i = 0; i < 300; i++) { if (i == 20){ thread.join();//Jump in line } System.out.println("main" + i); } } }
-
Thread state observation
-
Thread.State
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: the thread that is BLOCKED waiting for the monitor to lock is in this state
WAITING: the 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 execute the action for the specified waiting time is in this state.
TERMINATED: the exited thread is in this state
//Observe the status of the thread 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("///"); }); //Observe the state when the thread has not been opened Thread.State state = thread.getState(); System.out.println(state);//NEW //After the observation is started thread.start(); System.out.println(thread.getState()); while (state != Thread.State.TERMINATED){//As long as the thread does not terminate, it will always output the state Thread.sleep(1000); state = thread.getState();//Update 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)
//Test thread priority //Threads with higher thread optimization level do not necessarily execute first. public class TestPriority { public static void main(String[] args) { //Print 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); t1.setPriority(6); t1.start(); t2.setPriority(2); t2.start(); t3.setPriority(Thread.MAX_PRIORITY); t3.start(); t4.setPriority(1); t4.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 has completed execution
- 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 and waiting
//Daemon thread public class TestDaemon { public static void main(String[] args) { God god = new God(); Person person = new Person(); Thread thread = new Thread(god); thread.setDaemon(true);//Set daemon thread thread.start();//Open daemon thread thread = new Thread(person); thread.start();//Human thread start } } //lord class God implements Runnable{ @Override public void run() { while (true){ System.out.println("God is watching over you!"); } } } //people class Person implements Runnable{ @Override public void run() { for (int i = 0; i < 36500; i++) { System.out.println("People live happily every day"); } System.out.println("Say goodbye to the world---------------------------------"); } }
Thread synchronization mechanism
- Concurrency: the same object is operated by multiple threads at the same time
- Thread synchronization: when dealing with multithreading, multiple threads access the same object, and some threads also want to modify the object At this time, we need thread synchronization. Thread synchronization is 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.
- Queue and lock: in order to ensure the correctness of data access in the method, the lock mechanism synchronized is added during access. When one thread obtains the exclusive lock of the object and monopolizes resources, other threads must wait and release the lock after use. The following problems exist:
- Holding a lock by one thread will cause all other threads that need the lock to hang
- In multi thread 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.
Three examples of unsafe threads
//Unsafe ticket buying public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket buyTicket = new BuyTicket(); new Thread(buyTicket,"Forced me").start(); new Thread(buyTicket,"Awesome you").start(); new Thread(buyTicket,"Damn cattle").start(); } } class BuyTicket implements Runnable{ private int tickets = 10; boolean flag = true; @Override public void run() { while (flag){ Buy(); } } private void Buy(){ if (tickets<=0){ flag = false; } System.out.println(Thread.currentThread().getName() + "Bought the second" + tickets-- +"Ticket"); } }
//Unsafe withdrawal //Two people go to the bank to withdraw money and open an account public class UnsaftBank { public static void main(String[] args) { Account account = new Account(100,"Bank of China savings card"); new Drawing(account,50,"you").start(); new Drawing(account,100,"wife").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;//bank account //How much did you withdraw int drawingMoney; //How much money do you have now int nowMoney; public Drawing(Account account,int drawingMoney,String name){ super(name); this.account = account; this.drawingMoney = drawingMoney; } @Override public void run() { if (drawingMoney>account.money){ System.out.println(Thread.currentThread().getName()+"Sorry, the balance is insufficient!"); return; } //Thread hibernation, amplifying insecurity try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Card balance = balance - the money you withdraw account.money = account.money-drawingMoney; //The money in your hand nowMoney += drawingMoney; System.out.println(this.getName() + "Yes" + drawingMoney + "Ten thousand yuan"); System.out.println(this.getName()+"In hand" + nowMoney + "Ten thousand yuan"); System.out.println("Balance and" + account.money + "Ten thousand yuan"); } }
import java.util.ArrayList; import java.util.List; //Thread unsafe collection //It is possible that several threads operate at the same location at the same time 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(); } System.out.println(list.size()); } }
Synchronization method and synchronization block
-
Synchronization method
-
Synchronized keyword: there are two uses: synchronized method and synchronized block
Synchronization method: public synchronized void method(int args) {}
-
The synchronized method controls the access to "objects". Each object corresponds to a lock. Each synchronized method must obtain the lock of the object calling the method before it can be executed. Otherwise, the thread will be blocked. Once the method is executed, it will monopolize the lock until the method returns. The lock will not be released until the method returns. The blocked thread can obtain the lock and continue to execute
-
Defect: declaring a large method synchronized will affect efficiency
-
Disadvantages of synchronization method
Only the contents that need to be modified in the method need to be locked. Too many locks waste resources
-
Synchronization block
- synchronized(Obj){}
- Obj is called synchronization monitor
- Obj can use any object, but it is recommended to use shared resources as synchronization monitor
- 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.
Three unsafe thread modifications
//Unsafe ticket buying //Use synchronized to make threads safe public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket buyTicket = new BuyTicket(); new Thread(buyTicket,"Forced me").start(); new Thread(buyTicket,"Awesome you").start(); new Thread(buyTicket,"Damn cattle").start(); } } class BuyTicket implements Runnable{ private int tickets = 10; boolean flag = true;//External stop mode @Override public synchronized void run() { //Buy a ticket while (flag){ try { Buy(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void Buy() throws InterruptedException { if (tickets<=0){ flag = false; return; } //Analog delay Thread.sleep(100); System.out.println(Thread.currentThread().getName() + "Bought the second" + tickets-- +"Ticket"); } }
//Unsafe withdrawal //Two people go to the bank to withdraw money and open an account public class UnsaftBank { public static void main(String[] args) { Account account = new Account(1000,"Bank of China savings card"); new Drawing(account,50,"you").start(); new Drawing(account,100,"wife").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;//bank account //How much did you withdraw int drawingMoney; //How much money do you have now int nowMoney; public Drawing(Account account,int drawingMoney,String name){ super(name); this.account = account; this.drawingMoney = drawingMoney; } @Override public void run() { //The object of the lock is the amount of change synchronized (account){ if (drawingMoney>account.money){ System.out.println(Thread.currentThread().getName()+"Sorry, the balance is insufficient!"); return; } //Thread hibernation, amplifying insecurity try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Card balance = balance - the money you withdraw account.money = account.money-drawingMoney; //The money in your hand nowMoney += drawingMoney; System.out.println(this.getName() + "Yes" + drawingMoney + "Ten thousand yuan"); System.out.println(this.getName()+"In hand" + nowMoney + "Ten thousand yuan"); System.out.println("Balance and" + account.money + "Ten thousand yuan"); } } }
import java.util.ArrayList; import java.util.List; //Thread unsafe collection //It is possible that several threads operate at the same location at the same time public class UnsafeList { public static void main(String[] args) throws InterruptedException { List<String> list = new ArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread(()->{ synchronized (list){ list.add(Thread.currentThread().getName()); } }).start(); } Thread.sleep(3000);//Thread hibernation is not added here, but the data is abnormal because the main thread has finished running and the thread has not finished running System.out.println(list.size()); } }
CopyOnWriteArrayList
import java.util.concurrent.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(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } }
deadlock
Multiple threads are waiting for each other to release resources and stop execution
When a synchronization block has "locks of more than two objects" at the same time, the problem of "deadlock" may occur.
Four necessary conditions for deadlock generation:
- 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 before they are used up
- Circular waiting condition: a circular waiting resource relationship is formed between several processes.
Deadlock condition
public class DeadLock { public static void main(String[] args) { MakeUp g1 = new MakeUp(0,"Grey Gu Liang"); MakeUp g2 = new MakeUp(1,"Snow White"); g1.start(); g2.start(); } } //Lipstick class LipStick{ } //mirror class Mirror{ } //Make up class MakeUp extends Thread{ //A resource static LipStick lipStick = new LipStick(); static Mirror mirror = new Mirror(); int choice = 0;//Selection order String girlName; MakeUp(int choice,String girlName){ this.choice = choice; this.girlName = girlName; } @Override public void run() { makeup(); } private void makeup(){ if (choice == 0){ synchronized (lipStick){ System.out.println(this.girlName + "Got the lock of lipstick"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (mirror){ System.out.println(this.girlName + "Got the lock of the mirror"); } } }else { synchronized (mirror){ System.out.println(this.girlName + "Got the lock of the mirror"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lipStick){ System.out.println(this.girlName + "Got the lock of lipstick"); } } } } }
Resolve deadlock
public class DeadLock { public static void main(String[] args) { MakeUp g1 = new MakeUp(0,"Grey Gu Liang"); MakeUp g2 = new MakeUp(1,"Snow White"); g1.start(); g2.start(); } } //Lipstick class LipStick{ } //mirror class Mirror{ } //Make up class MakeUp extends Thread{ //A resource static LipStick lipStick = new LipStick(); static Mirror mirror = new Mirror(); int choice = 0;//Selection order String girlName; MakeUp(int choice,String girlName){ this.choice = choice; this.girlName = girlName; } @Override public void run() { makeup(); } private void makeup(){ if (choice == 0){ synchronized (lipStick){ System.out.println(this.girlName + "Got the lock of lipstick"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (mirror){ System.out.println(this.girlName + "Got the lock on the mirror"); } }else { synchronized (mirror){ System.out.println(this.girlName + "Got the lock of the mirror"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } synchronized (lipStick){ System.out.println(this.girlName + "Got the lock of lipstick"); } } } }
Lock lock
-
JDK5.0 has provided a more powerful thread synchronization mechanism -- synchronization is achieved by explicitly defining synchronization Lock objects. Synchronous locks use Lock objects to act 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 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.
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //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 private final ReentrantLock lock = new ReentrantLock(); @Override public void run() { while (true){ try{ lock.lock(); if (ticketNums>0){ System.out.println(ticketNums--); }else { break; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }finally { lock.unlock(); } } } }
Production consumer model
Application scenario: producer and consumer issues
- Assuming that only one 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 is no product in the warehouse, the producer will put the product into the warehouse, otherwise stop production and wait until the product in the warehouse is taken away by the consumer.
- If there is a product in the warehouse, the consumer can take the product away for consumption, otherwise stop consumption and wait until the product is put into the warehouse again.
This is a problem of thread synchronization. Producers and consumers share the same resource, and producers and consumers are interdependent and conditional on each other.
-
For producers, before producing products, they should inform consumers to wait, and after producing products, they need to inform consumers to consume immediately
-
For consumers, after consumption, they should inform producers that they have finished consumption and need to produce new products for consumption.
-
In the production and consumer problems, synchronized is not enough
- synchronized can prevent concurrent updating of the same shared resource and realize synchronization
- synchronized cannot be used for message passing (Communication) between different threads
-
Java provides several methods to solve the communication problem between threads
Method name effect wait() It means that the thread waits until other threads notify it. Unlike sleep, it will release the lock 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 an exception IIIegalMonitorStateException will be thrown
Concurrent collaboration model "producer / consumer model" -- > management method
-
Producer: the module responsible for production data (may be method, object, thread, process)
-
Consumer: module responsible for processing data (may be method, object, thread, 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 out the data from the buffer
//Test: producer consumer model -- > using buffer solution: pipe process method //Producer, consumer, product, buffer public class TestPC { public static void main(String[] args) { SynContainer container = new SynContainer();//Create buffer object new Productor(container).start(); new Consumer(container).start(); } } //producer class Productor extends Thread{ SynContainer synContainer; public Productor(SynContainer synContainer){ this.synContainer = synContainer; } @Override public void run() { for (int i = 1; i <= 100; i++) { Chicken chicken = new Chicken(i); synContainer.push(chicken);//Put in buffer System.out.println("Produced the second" + i + "Chicken"); } } } //consumer class Consumer extends Thread{ SynContainer synContainer; public Consumer(SynContainer synContainer){ this.synContainer = synContainer; } @Override public void run() { for (int i = 0; i < 100; i++) { Chicken pop = synContainer.pop(); System.out.println("Consumed the second" + pop.foodId + "Chicken"); try { Thread.sleep(300);//Control the time to prevent consumption before production } catch (InterruptedException e) { e.printStackTrace(); } } } } //product class Chicken{ int foodId; public Chicken(int foodId) { this.foodId = foodId; } } //buffer class SynContainer{ Chicken[] chickens = new Chicken[10];//Buffer size, type is access product int count = 0;//Buffer counter //Producers put in products public synchronized void push(Chicken chicken){ //If the container is full, inform the consumer to consume if (count == chickens.length-1){ //Inform consumers of consumption Producer 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(){ //If the container is empty, stop consumption if (count ==0){ //Consumers wait, producers produce 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; } }
Concurrent collaboration model "producer / consumer model" -- > semaphore method
//Producer, consumer mode -- > semaphore method //Using flag bit control //Performer, viewer, program public class TestPC2 { public static void main(String[] args) { Tv tv = new Tv(); new Player(tv).start(); new Watcher(tv).start(); } } //performer class Player extends Thread{ Tv tv; public Player(Tv tv){ this.tv = tv; } @Override public void run() { for (int i = 0; i < 10; i++) { if (i%2 == 0){ this.tv.Programe("Action blockbuster"); }else { this.tv.Programe("Love action blockbuster"); } } } } //Viewer class Watcher extends Thread{ Tv tv; public Watcher(Tv tv){ this.tv = tv; } @Override public void run() { for(int i=0;i<10;i++){ this.tv.Watch(); } } } //Products -- programs class Tv{ //The performer performs and the viewer waits //The audience watched and the actors waited String programme;//program boolean flag = true; //perform public synchronized void Programe(String programme){ if (!flag){ //Actor waiting try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("The actors performed:" + programme); //Inform the audience to watch this.flag = !this.flag; this.notifyAll();//Notification wake-up this.programme = programme; } //Watch the program public synchronized void Watch(){ if (flag){ try { this.wait();//wait for } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("The audience watched:" + programme); //Inform the actors to perform this.notifyAll(); this.flag = !this.flag; } }
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.
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.
Benefits: increased responsiveness
Reduce resource consumption
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
JDK 5.0 provides thread pool related API s: 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
Future submit (Callable task): when a task is executed and there is a return value, it usually executes Callable
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
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //Test thread pool public class TestPool { public static void main(String[] args) { //Create service and thread pool //newFixedThreadPool ExecutorService service = Executors.newFixedThreadPool(10); //implement service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); //Close link service.shutdown(); } } class MyThread implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }