Detailed explanation of multithreading
1, Thread introduction
Processes and threads:
2, Thread Basics
Common method calls and multithreading:
1. Thread creation
There are three ways to create threads:
- Thread.class: inherits the thread class.
- Runable interface: implements the Runnable interface.
- Callable interface: implements the callable interface.
Inherit thread Class implements multithreading (not recommended because it is limited by single inheritance):
- 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
Note: the thread does not necessarily execute immediately after starting, but is scheduled by the CPU.
package demo01; /** * 1. Thread creation method 1: inherit the thread class, rewrite the run () method, and call start to start the thread 2. 3. The thread is scheduled by the CPU, and the summary is not executed immediately. 4. */ public class TestThread1 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---"+1); } } public static void main(String[] args){ /** * * main Main thread * * Create a thread object */ TestThread1 testThread1 = new TestThread1(); //Call the start () method to start the thread. testThread1.start(); for (int i = 0; i < 1000; i++) { System.out.println("I'm learning multithreading--"); } } }
The test found that they were executed separately.
Implement the Runnable interface to realize the thread (recommended to avoid the limitation of single inheritance, flexible and convenient, so that the same object can be used by multiple threads):
- Define the MyRunnable class to implement the Runnable interface
- Implement the run() method and write the thread execution body
- Create a thread object and call the start() method to start the thread
package demo01; /** * * Implement the runnable interface and rewrite the run method. The execution thread needs to drop into the runnable interface implementation class and call the start method. * */ public class TestThread2 implements Runnable { @Override public void run() { // run method thread body for (int i = 0; i < 200; i++) { System.out.println("I'm looking at the code---"+1); } } public static void main(String[] args){ /** * * Create the implementation class object of runnable interface * * Create a thread object and start our thread agent through the thread object */ TestThread2 testThread2 = new TestThread2(); // Thread thread = new Thread(testThread2); // // thread.start(); // Abbreviation new Thread(testThread2).start(); for (int i = 0; i < 1000; i++) { System.out.println("I'm learning multithreading--"); } } }
Multithreading through Callable interface
Introduction to the allable interface:
- java.util.concurrent.Callable is a generic interface with only one call() method
- The all() method throws an Exception and returns a specified generic class object
The Callable interface implements multithreading application scenarios
- When the parent thread wants to get the running results of the child thread
Steps to implement multithreading using Callable interface
- Create an instantiated object of a subclass of Callable
- Create a FutureTask object and pass the Callable object into the construction method of FutureTask
- Instantiate the Thread object and pass in the FurureTask object in the constructor
- Start thread
Thread implementation using Callable interface:
package demo01; import java.util.concurrent.Callable; public class TestThread4 implements Callable<String> { @Override public String call() throws Exception { // TODO Auto-generated method stub System.out.println("====="); return "9999"; } }
package demo01; import java.util.concurrent.FutureTask; public class TestThread5 { public static void main(String[] args) { FutureTask<String> ft = new FutureTask<>(new TestThread4()); new Thread(ft).start(); } }
Anonymous classes and subclasses implement the Callable interface to create sub threads
package demo01; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class TestThread3 { public static void main(String[] args) { Callable<String> cl = new Callable<String>() { @Override public String call() throws Exception { System.out.println(Thread.currentThread().getName() + "Marching~~~"); System.out.println(Thread.currentThread().getName() + "Encounter the enemy~~~"); System.out.println(Thread.currentThread().getName() + "Kill the enemy bravely!!!!"); return "The battle was won and 50000 enemy troops were captured"; } }; FutureTask<String> ft = new FutureTask(cl); new Thread(ft, "Li cunxiao troops").start(); try { Thread.currentThread().setName("Li Cunxu troops"); Thread.sleep(3000); System.out.println(Thread.currentThread().getName() + "Rest 3000 ms"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "After rectification, wait for news from friendly forces..."); try { String str = ft.get(); System.out.println("Li Cunxu's troops learned that the news of the friendly forces was:" + str); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }
2. Thread status
- Creation status: Thread t = new Thread() once the thread object is created, it enters the new state.
- Ready state: when the start () method is called, the thread immediately enters the ready state, but it does not mean that the execution is scheduled immediately.
- Running state: when the thread in the ready state is scheduled by the cpu, the thread enters the running state. At this time, the thread will execute the code of the thread body.
- Blocking state: when the sleep, wait or synchronization lock is called, the thread enters the blocking state. After the blocking state contacts, the thread will return to the ready state and wait for the cpu to schedule and execute.
- Dead state: the thread is interrupted or terminated. Once it enters the dead state, it cannot be started again.
3. Thread method
4. Thread stop
The stop() and destroy() methods provided by JDK are not recommended (obsolete).
It is recommended that the thread stop by itself. It is recommended to use a flag bit to terminate the variable. When flag = false, the thread is terminated.
Chestnuts:
package state; /** * Test stop * 1.It is recommended that the thread be stopped normally -- > utilization times, and dead loop is not recommended * 2.It is recommended to use flag bit -- > to set a flag bit * 3.Do not use outdated methods such as stop or destroy, or methods that are not recommended by JDK */ public class TestStop implements Runnable { // 1. Set a flag bit private boolean flag = true; @Override public void run() { int i = 0; while (flag) { System.out.println("run...Thread" + i++); } } // 2. Set a public method to stop the thread and convert the flag bit public void stop() { this.flag = false; } public static void main(String[] args) { TestStop stop = new TestStop(); new Thread(stop).start(); for (int i = 0; i < 1000; i++) { System.out.println("main..." + i); if (i == 900) { //Call stop() to switch the flag bit and let the thread terminate stop.stop(); System.out.println("The thread stopped"); } } } }
5. Thread hibernation
- sleep specifies the number of milliseconds that the current thread is blocked;
- There is an exception InterruptedException in sleep;
- After the sleep time reaches, the thread enters the ready state;
- sleep can simulate network delay, countdown, etc;
- Each object has a lock, and sleep will not release the lock;
6. Comity
- Comity thread: pause the currently executing thread without blocking;
- Change the thread from running state to ready state;
- Let the cpu reschedule, comity is not necessarily successful! kan CPU scheduling;
Chestnuts:
package state; /** * Test comity thread * Comity does not necessarily succeed. It depends on your mood */ public class TestYield { public static void main(String[] args) { MyYeild myYeild = new MyYeild(); new Thread(myYeild, "a").start(); new Thread(myYeild, "b").start(); } } class MyYeild implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + "The thread starts executing"); Thread.yield();//Comity System.out.println(Thread.currentThread().getName() + "Thread stop execution"); } }
7. Thread enforcement
Join merge threads. After this thread is executed, other threads are executed, and other threads are blocked. It can be imagined as queue jumping.
Chestnuts:
package state; /** * Test join * Jump in line */ public class TestJoin implements Runnable { @Override public void run() { for (int i = 0; i < 500; i++) { System.out.println("thread vip" + i); } } public static void main(String[] args) throws InterruptedException { //Start our thread TestJoin joinThread = new TestJoin(); Thread thread = new Thread(joinThread); thread.start(); //Main thread for (int i = 0; i < 500; i++) { if (i == 200) { thread.join();//Jump in line } System.out.println("main" + i); } } }
8. Thread priority
Chestnuts:
package state; public class ThreadPriority { public static void main(String[] args) { //Default priority of main thread System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority()); MyPriority myPriority = new MyPriority(); Thread thread1 = new Thread(myPriority); Thread thread2 = new Thread(myPriority); Thread thread3 = new Thread(myPriority); Thread thread4 = new Thread(myPriority); Thread thread5 = new Thread(myPriority); //Set priority before starting thread1.start(); thread2.setPriority(1); thread2.start(); thread3.setPriority(4); thread3.start(); thread4.setPriority(Thread.MAX_PRIORITY);//MAX_PRIORITY=10 thread4.start(); thread5.setPriority(8); thread5.start(); } } class MyPriority implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority()); } }
9. 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
- Such as recording operation logs in the background, monitoring memory and garbage collection
Chestnuts:
package state; public class DaemonThread {public static void main(String[] args) { God god = new God(); You you = new You(); Thread thread = new Thread(god); //The default false indicates that it is a user thread. Normal threads are user threads thread.setDaemon(true); //God daemon thread start thread.start(); //Your user thread starts new Thread(you).start(); } } /** * lord */ class God implements Runnable{ @Override public void run() { while (true){ System.out.println("God bless you"); } } } /** * you */ 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===="); } }
3, Thread synchronization
Multiple threads operate on the same resource:
Thread synchronization:
Unsafe thread cases:
Ticket purchase:
package state; public class UnsafeBuyTicket { public static void main(String[] args) { BuyTicket buyTicket = new BuyTicket(); new Thread(buyTicket, "Zhang San").start(); new Thread(buyTicket, "Li Si").start(); new Thread(buyTicket, "Wang Wu").start(); } } class BuyTicket implements Runnable { //ticket private int ticketNums = 10; boolean flag = true; @Override public void run() { //Buy a ticket while (flag) { try { buy(); } catch (Exception e) { e.printStackTrace(); } } } //Buy a ticket private void buy() { //Judge whether there are tickets if (ticketNums <= 0) { flag = false; return; } //delay try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } //Buy a ticket System.out.println(Thread.currentThread().getName() + "Get" + ticketNums--); } }
Bank withdrawal:
package state; public class UnsafeBank { public static void main(String[] args) { Account account = new Account(100, "Marriage fund"); Drawing you = new Drawing(account, 50, "Exhibition hall"); Drawing girlfriend = new Drawing(account, 100, "sad"); you.start(); girlfriend.start(); } } //account class Account { int money;//balance String cardName;//Card name public Account(int money, String cardName) { this.money = money; this.cardName = cardName; } } //Bank: simulated withdrawal class Drawing extends Thread { Account account;//account int drawingMoney;//Withdrawal amount int nowMoney;//The money in your hand public Drawing(Account account, int drawingMoney, String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } //Withdraw money @Override public void run() { //Judge whether you have money if (account.money - drawingMoney < 0) { System.out.println(Thread.currentThread().getName() + "Sorry, your credit is running low,Cannot withdraw money"); return; } try { Thread.sleep(1000);//Amplify the occurrence of the problem } catch (InterruptedException e) { e.printStackTrace(); } //Amount in card = balance - your money account.money = account.money - drawingMoney; //The money in your hand nowMoney = nowMoney + drawingMoney; System.out.println(account.cardName + "The balance is:" + account.money); //this.getName()==Thread.currentThread().getName() System.out.println(this.getName() + "Money in hand:" + nowMoney); } }
Thread unsafe collection:
ublic class Demo26_UnsafeList { public static void main(String[] args) { List<String> list = new ArrayList<String>(); for (int i = 0; i < 1000; i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } System.out.println(list.size()); } }
Synchronization method
Disadvantages:
Synchronization block:
Use synchronized to solve the above cases:
Ticket buying questions:
package state; public class UnsafeBuyTicket2 { public static void main(String[] args) { BuyTicket1 buyTicket = new BuyTicket1(); new Thread(buyTicket, "Zhang San").start(); new Thread(buyTicket, "Li Si").start(); new Thread(buyTicket, "Wang Wu").start(); } } class BuyTicket1 implements Runnable { //ticket private int ticketNums = 10; boolean flag = true; @Override public void run() { //Buy a ticket while (flag) { try { buy(); } catch (Exception e) { e.printStackTrace(); } } } //The synchronized synchronization method locks this private synchronized void buy() { //Judge whether there are tickets if (ticketNums <= 0) { flag = false; return; } //delay try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } //Buy a ticket System.out.println(Thread.currentThread().getName() + "Get" + ticketNums--); } }
Banking issues:
package state; public class UnsafeBank2 { public static void main(String[] args) { Account1 account = new Account1(100, "Marriage fund"); Drawing1 you = new Drawing1(account, 50, "Exhibition hall"); Drawing1 girlfriend = new Drawing1(account, 100, "sad"); you.start(); girlfriend.start(); } } //account class Account1 { int money;//balance String cardName;//Card name public Account1(int money, String cardName) { this.money = money; this.cardName = cardName; } } //Bank: simulated withdrawal class Drawing1 extends Thread { Account1 account;//account int drawingMoney;//Withdrawal amount int nowMoney;//The money in your hand public Drawing1(Account1 account, int drawingMoney, String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } //Withdraw money @Override public void run() { //The object of the lock is the quantity of the variable, which needs to be added, deleted, modified and queried synchronized (account) { //Judge whether you have money if (account.money - drawingMoney < 0) { System.out.println(Thread.currentThread().getName() + "Sorry, your credit is running low,Cannot withdraw money"); return; } try { Thread.sleep(1000);//Amplify the occurrence of the problem } catch (InterruptedException e) { e.printStackTrace(); } //Amount in card = balance - your money account.money = account.money - drawingMoney; //The money in your hand nowMoney = nowMoney + drawingMoney; System.out.println(account.cardName + "The balance is:" + account.money); //this.getName()==Thread.currentThread().getName() System.out.println(this.getName() + "Money in hand:" + nowMoney); } } }
Set questions:
//Thread safe collection synchronization block public class Demo29_SafeList { public static void main(String[] args) { List<String> list = new ArrayList<String>(); for (int i = 0; i < 1000; i++) { new Thread(() -> { synchronized (list) { list.add(Thread.currentThread().getName()); } }).start(); } try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); } }
4, Deadlock
How to avoid deadlock:
5, Lock lock
The difference between synchronized and Lock:
Chestnuts:
package state; import java.util.concurrent.locks.ReentrantLock; 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 ReentrantLock reentrantLock = new ReentrantLock(); @Override public void run() { while (true) { try { reentrantLock.lock(); //Lock if(ticketNums > 0 ){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "Purchased the second" + ticketNums-- + "Ticket"); } else { break; } } finally { //Unlock reentrantLock.unlock(); } } } }
6, Thread communication
Application scenario: problems of producers and consumers
Java provides several methods to solve the communication problem between threads:
Solution:
- Concurrent collaboration mode "producer / consumer mode" = = = > management method
- Producer: module responsible for production data (may be method, object, thread, array)
- Consumer: the module responsible for processing data (possibly methods, objects, threads, arrays)
- Buffer: consumers cannot directly use the data of producers. There is a buffer between them
Put the data from the producer into the buffer
//Test producer consumer model -- > pipe process method //product public class Product { private int id; public Product(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } } //consumer public class ConsumerThread extends Thread { private SyncContainer syncContainer; public ConsumerThread(SyncContainer syncContainer) { this.syncContainer = syncContainer; } @Override public void run() { for (int i = 0; i < 100; i++) { Product pop = syncContainer.pop(); System.out.println("Consumed the second"+ pop.getId() + "Product No"); } } } //producer public class ProviderThread extends Thread { //Created buffer private SyncContainer syncContainer; public ProviderThread(SyncContainer syncContainer) { this.syncContainer = syncContainer; } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("Produced" + i + "Chicken!"); syncContainer.push(new Product(i)); } } } //container public class SyncContainer { //Container size Product[] products = new Product[10]; //Container counter int count = 0; //Producers put in products public synchronized void push(Product product){ //If the container is full, wait for the consumer //Inform consumers to consume and producers to wait if(count == products.length) { try { this.wait(); } catch (InterruptedException e){ e.printStackTrace(); } } //If the container is not full, produce the product products[count] = product; count++; //Consumers can be notified of consumption this.notifyAll(); } //Consumer products public synchronized Product pop(){ //Determine whether the container is empty if(count == 0){ //Inform the producer of production Consumer waiting try { this.wait(); } catch (InterruptedException e){ e.printStackTrace(); } } //If you can consume count--; Product product = products[count]; //Inform the producer of production this.notifyAll(); return product; } } public class Main { public static void main(String[] args) { SyncContainer container = new SyncContainer(); new ProviderThread(container).start(); new ConsumerThread(container).start(); } }
- Concurrent collaboration mode "producer / consumer mode" = = = > semaphore method
//Products -- > Programs public class TV { //The actors performed and the audience waited //The audience watched and the actors waited String voice; //A performance boolean flag = true; //perform public synchronized void play(String voice) { if(!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("The actors performed" + voice); //Inform the audience to watch this.voice = voice; this.notifyAll(); this.flag = !flag; } //watch public synchronized void watch(){ if(flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("The audience watched" + voice); //Inform the actors to perform this.notifyAll(); this.flag = !flag; } } public class Player extends Thread { private TV tv = null; public Player(TV tv) { this.tv = tv; } @Override public void run() { for (int i = 0; i < 100; i++) { tv.play("Performed" + i + "Program No"); } } } public class Watcher extends Thread { private TV tv = null; public Watcher(TV tv) { this.tv = tv; } @Override public void run() { for (int i = 0; i < 100; i++) { tv.watch(); } } } //Test the problems of producers and consumers: signal lamp method and sign bit solution public class Main { public static void main(String[] args) { TV tv = new TV(); new Watcher(tv).start(); new Player(tv).start(); } }
Use thread pool: