Multithreading
Create thread
There are three ways to create threads
- Inherit the Thread class and override the run method
- Implement Runnable interface
- Implement Callable interface
Inherit Thread class
Inherit the Thread class and override the run method
package Thread; public class MyThread extends Thread{ @Override public void run() { for(int i = 0;i<100;i++){ System.out.println("Child thread..........."+i); } } }
package Thread; public class TestThread { public static void main(String[] args) { //Create thread object MyThread myThread = new MyThread(); //2 start the thread. Using the run method is equivalent to calling the run method by the object. It is a single thread myThread.start(); //Main thread execution for (int i = 0;i < 50;i++){ System.out.println("Main thread============"+i); } } }
Get thread name
Get thread ID and thread name
1. invoke this. in the subclass of Thread Getid () or this getName()
2. Use thread currentThread(). Getid () and thread currentThread (). getName ()
3. Modify thread name
Call the setName() method of the thread object.
Use the constructor of thread subclass to assign values.
public void run() { for(int i = 0;i<100;i++){ //this.getId get thread Id //this.getName get thread name //The first method needs to inherit the Thread class System.out.println("thread id: "+this.getId()+"Thread name"+getName()+"Child thread..........."+i); } //The second method is thread Currentthread() gets the current thread System.out.println("thread id: "+Thread.currentThread()+"Thread Name:"+Thread.currentThread().getName());
Get and modify thread name
Modify thread name
Call the setName() method of the thread object.
Use the constructor of thread subclass to assign values.
//Modify thread name MyThread myThread = new MyThread(); myThread.setName("My child thread 1"); myThread.start(); MyThread myThread2 = new MyThread(); myThread2.setName("My child thread 2"); myThread2.start();
The second method: use super to pass the name to the Thread class
//Add construction method public MyThread(){ } public MyThread(String name){ super(name);//Pass name to Thread class with super } MyThread myThread = new MyThread("My child thread 1"); MyThread myThread2 = new MyThread("My child thread 2");
Examples
Each class uses 100 inheritance windows to sell 4 tickets
package Thread; public class TicketWin extends Thread{ //Add a construction method. After adding, you can simply delete getName public TicketWin(){} public TicketWin(String name){ super(name); } private int ticket = 100;//Number of votes @Override public void run() { //Ticket selling function while(true){ if(ticket<=0){ break; } System.out.println(Thread.currentThread().getName()+"Bought the second"+ticket+"Ticket"); ticket--; } } }
package Thread; public class TestWin { public static void main(String[] args) { //Create four windows TicketWin w1 = new TicketWin("Window 1"); TicketWin w2 = new TicketWin("Window 2"); TicketWin w3 = new TicketWin("Window 3"); TicketWin w4 = new TicketWin("Window 4"); //Start thread w1.start(); w2.start(); w3.start(); w4.start(); } }
Create thread (2)
Second implementation method: Runnable interface
package Thread; public class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0;i < 100;i++){ System.out.println(Thread.currentThread().getName()+"...."+i); } } }
package Thread; public class TestRunnable { public static void main(String[] args) { //1 create a MyRunnable object to represent the function to be executed MyRunnable runnable = new MyRunnable(); //2 create thread object Thread thread = new Thread(runnable,"My thread 1"); //3 start thread.start(); for (int i = 0;i<50;i++){ System.out.println("main....."+i); } } }
Anonymous Inner Class
Runnable runnable = new Runnable() { @Override public void run() { for (int i = 0;i<50;i++){ System.out.println("main....."+i); } } }; //Create thread object Thread thread = new Thread(runnable,"My thread 1"); thread.start(); } }
Runnable case 1
1. Sell 100 tickets in 4 windows
package Thread2; public class Ticket implements Runnable{ private int ticket = 100;//100 tickets @Override public void run() { while(true){ if (ticket<=0){ break; } System.out.println(Thread.currentThread().getName()+"Bought the second"+ticket+"Ticket"); ticket--; } } }
package Thread2; public class TestTicket { public static void main(String[] args) { //1 create ticket object Ticket ticket = new Ticket(); //2 create thread object Thread w1 = new Thread(ticket,"Window 1"); Thread w2 = new Thread(ticket,"Window 2"); Thread w3 = new Thread(ticket,"Window 3"); Thread w4 = new Thread(ticket,"Window 4"); //3 start thread w1.start(); w2.start(); w3.start(); w4.start(); } }
Question: four windows will rob 100 tickets
Runnable case 2
2. You and your girlfriend share a bank card. You deposit money in the card, and your girlfriend withdraws money from the card. Use the program
Simulation process?
Create two classes: deposit and withdraw
package Thread2; public class AddMoney implements Runnable{ private BankCard card;//BankCard public AddMoney(BankCard card){ this.card = card; } @Override public void run() { for (int i = 0 ; i<10;i++){ card.setMoney(card.getMoney()+1000); System.out.println(Thread.currentThread().getName()+"Saved 1000,The balance is:"+card.getMoney()); } } }
package Thread2; public class SubMoney implements Runnable{ private BankCard card; public SubMoney(BankCard card){ this.card = card; } @Override public void run() { for (int i = 0;i<10;i++){ if(card.getMoney()>=1000){ card.setMoney(card.getMoney()-1000); System.out.println(Thread.currentThread().getName()+"After withdrawing 1000, the balance is:"+card.getMoney()); }else{ System.out.println("The balance is not enough. Please save money quickly"); i++; } } } }
start-up
package Thread2; public class TestBankCard { public static void main(String[] args) { //1 create a bank card BankCard card = new BankCard(); //2. Create, save and withdraw money AddMoney add = new AddMoney(card); SubMoney sub = new SubMoney(card); //3 create two threads Thread zhangge = new Thread(add,"Brother Zhang"); Thread jingjing = new Thread(sub,"Quiet"); //4 start thread zhangge.start(); jingjing.start(); //Thread safety issues } }
The introduction is written inversely, using anonymous inner classes
package Thread2; public class TestBankCard2 { public static void main(String[] args) { BankCard card = new BankCard(); //save money Runnable add = new Runnable() { @Override public void run() { for (int i = 0 ; i<10;i++){ card.setMoney(card.getMoney()+1000); System.out.println(Thread.currentThread().getName()+"Saved 1000,The balance is:"+card.getMoney()); } } }; //Withdraw money Runnable sub = new Runnable() { @Override public void run() { for (int i = 0;i<10;i++){ if(card.getMoney()>=1000){ card.setMoney(card.getMoney()-1000); System.out.println(Thread.currentThread().getName()+"After withdrawing 1000, the balance is:"+card.getMoney()); }else{ System.out.println("The balance is not enough. Please save money quickly"); i++; } } } }; //Create a thread object and start new Thread(add,"Clearly").start(); new Thread(sub,"Xiao Hong").start(); } }
Thread status (basic)
Thread sleep
Sleep:
public static void sleep(long millis)
The current thread actively sleeps millis econd
package Thread2; public class TestSleep extends Thread{ public static void main(String[] args) { SleepThread s1 = new SleepThread(); s1.start(); SleepThread s2 = new SleepThread(); s2.start(); } @Override public void run() { for (int i = 0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"..."+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }//The subclass cannot throw more exceptions than the parent class. try/catch } } }
Waiver:
public static void yield()
The current thread actively abandons the time slice and returns to the ready state to compete for the next time slice.
package Thread2; public class YieldThread extends Thread{ @Override public void run() { for (int i = 0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"..."+i); //Actively abandon cpu Thread.yield(); } } }
Thread join:
public final void join()
Allow other threads to join the current thread
j1.join();//Join the current thread (main) and block the current thread until the execution of the join thread is completed
package Thread2; public class TestJoin extends Thread{ public static void main(String[] args) { JoinThread j1 = new JoinThread(); j1.start(); try { j1.join();//Join the current thread (main) and block the current thread until the execution of the join thread is completed } catch (InterruptedException e) { e.printStackTrace(); } //for main thread for(int i = 0;i<20;i++){ System.out.println(Thread.currentThread().getName()+"======"+i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public void run() { for(int i = 0;i<30;i++){ System.out.println(Thread.currentThread().getName()+"..."+i); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Set thread priority and guard thread
Priority:
Thread object setPriority(),
The thread priority is 1-10, and the default is 5. The higher the priority, the more opportunities to obtain CPU.
Daemon thread:
Thread object setDaemon(true); Set as daemon thread
There are two types of threads: user thread (foreground thread) and daemon thread (background thread).
If all foreground threads in the program are executed, the background thread will automatically end.
The garbage collector thread is a daemon thread.
package Thread2; public class PriorityThread extends Thread{ @Override public void run() { for (int i = 0;i<50;i++){ System.out.println(Thread.currentThread().getName()+"===="+i); } } public static void main(String[] args) { PriorityThread p1 = new PriorityThread(); p1.setName("p1"); PriorityThread p2 = new PriorityThread(); p2.setName("p2"); PriorityThread p3 = new PriorityThread(); p3.setName("p3"); p1.setPriority(1); p3.setPriority(10); //start-up p1.start(); p2.start(); p3.start(); } }
Daemon thread
package Thread2; public class TestDeamon { public static void main(String[] args) { //Create thread (default foreground thread) DeamonThread d1 = new DeamonThread(); //Set as the daemon thread. After the foreground thread (d1) executes, the background thread (main) will end d1.setDaemon(true); d1.start(); for (int i = 0;i<10;i++){ System.out.println("Main thread-------------"); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Status of the thread (waiting)
Thread safety issues
package Thread2; import java.util.Arrays; public class ThreadSafe { private static int index = 0; public static void main(String[] args) throws Exception { //Create array String[] s = new String[5]; //Create two operations Runnable runnableA = new Runnable() { @Override public void run() { s[index] = "hello"; index++; } }; Runnable runnableB = new Runnable() { @Override public void run() { s[index] = "world"; index++; } }; //Create two thread objects Thread a = new Thread(runnableA,"A"); Thread b = new Thread(runnableB,"B"); a.start(); b.start(); a.join(); b.join(); System.out.println(Arrays.toString(s)); } }
It is possible that one thread has not finished executing, and another thread has overwritten the result of the previous thread
Thread safety
Synchronization mode
Synchronized (critical resource object) {/ / shackle the critical resource object
//Code (atomic operation), run first
}
Each object has a mutex tag to assign to the thread.
Only the thread with the object mutex flag can enter the synchronous code block that locks the object. When a thread exits a synchronized code block, the corresponding mutex flag is released.
My understanding is that after locking, you have to wait for the code (atomic operation) to complete before you have the next operation
After locking, other threads can only run after the running code is completed
Runnable runnableA = new Runnable() { @Override public void run() { //Synchronous code block synchronized (s){ s[index] = "hello"; index++; } } }; Runnable runnableB = new Runnable() { @Override public void run() { synchronized (s){ s[index] = "world"; index++; } } };
Synchronous code block usage (1)
@Override public void run() { while(true){ if (ticket<=0){ break; } System.out.println(Thread.currentThread().getName()+"Bought the second"+ticket+"Ticket"); ticket--; } }
Analysis: there are 4 windows and 100 tickets. If the first window will execute after getting the CPU and sell the 100th ticket, but there may be no ticket --, the time segment will arrive. At this time, the ticket is still 100, and at this time, the second window will get the CPU and sell the 100th ticket, and so on, there will be repetition.
public class Ticket implements Runnable{ private int ticket = 100;//100 tickets //Create lock private Object obj = new Object(); @Override public void run() { while(true){ synchronized (obj){ if (ticket<=0){ break; } } System.out.println(Thread.currentThread().getName()+"Bought the second"+ticket+"Ticket"); ticket--; } } }
You cannot create an object at the critical resource object in the lock, synchronized(new Object()), which means that each thread creates a lock every time it comes in. It is equivalent to a house. A person (thread) can only have one lock. After it is used up, another person (thread) can be changed. If a lock is created, other people (thread) will still enter.
sure
private int obj = new Object();
synchronized(new Object())
it's fine too
synchronized(this);
this is the ticket and the only one
Synchronous code block usage (2)
package Thread2; public class TestBankCard { public static void main(String[] args) { BankCard card = new BankCard(); Object obj =new Object(); //save money Runnable add = new Runnable() { @Override public void run() { for (int i = 0 ; i<10;i++){ synchronized (obj){ card.setMoney(card.getMoney()+1000); System.out.println(Thread.currentThread().getName()+"Saved 1000,The balance is:"+card.getMoney()); } } } }; //Withdraw money Runnable sub = new Runnable() { @Override public void run() { for (int i = 0;i<10;i++){ synchronized (obj){ if(card.getMoney()>=1000){ card.setMoney(card.getMoney()-1000); System.out.println(Thread.currentThread().getName()+"After withdrawing 1000, the balance is:"+card.getMoney()); }else{ System.out.println("The balance is not enough. Please save money quickly"); i--; } } } } }; new Thread(add,"Clearly").start(); new Thread(sub,"Xiao Hong").start(); } }
Synchronization method
Synchronization method:
synchronized return value type method name (parameter list 0) {/ / lock the current object (this)
//Code (atomic operation)
}
Only the thread with the mutex mark of the object can enter the synchronization method of locking the object.
When the thread exits the synchronization method, the corresponding mutex flag is released.
public class Ticket implements Runnable { private int ticket = 100;//100 tickets //Create lock //private Object obj = new Object(); @Override public void run() { while (true) { if(!sale()){ break; } } } //Selling tickets public synchronized boolean sale() {//Lock this static method to lock ticket class if (ticket <= 0) { return false; } System.out.println(Thread.currentThread().getName() + "Bought the second" + ticket + "Ticket"); ticket--; return true; } }
Synchronization rules
be careful:
The lock mark of the object is required only when calling a method containing a synchronized code block or a synchronized method.
If you call a method that does not contain a synchronous code block or an ordinary method, you do not need a lock mark and can call it directly.
Known thread safe classes in JDK:
StringBuffer
Vector
Hashtable
The disclosed methods in the above classes are synchronous methods modified by synchronized.
deadlock
Deadlock:
A deadlock occurs when the first thread has the a object lock mark and waits for the B object lock mark, while the second thread has the B object lock mark and waits for the a object lock mark.
A thread can have lock marks of multiple objects at the same time. When the thread is blocked, it will not release the lock marks it already has, which may cause deadlock.
public class Boy extends Thread{ @Override public void run() { synchronized (MyLock.a) { System.out.println("The boy got it a"); synchronized (MyLock.b) { System.out.println("The boy got it b"); System.out.println("The boy can eat"); } } } }
public class Girl extends Thread{ @Override public void run() { synchronized (MyLock.b) { System.out.println("The girl got it b"); synchronized (MyLock.a) { System.out.println("The girl got it a"); System.out.println("The girl can eat"); } } } }
public class MyLock extends Thread{ public static Object a = new Object(); public static Object b = new Object(); public static void main(String[] args) { Boy boy = new Boy(); Girl girl = new Girl(); boy.start(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } girl.start(); } }
Thread communication
Wait:
public final void wait()
public final void wait(long timeout)
It must be in the synchronization code block that locks obj. In a thread, call obj.. When waiting(), this thread
Put all the lock marks it has. At the same time, this thread is blocked in o's waiting queue. Release the lock and enter the waiting queue.
Notice:
public final void notify()
public final void notifyAl1()
Deposit and withdraw money
Add
package Thread3; public class Add implements Runnable{ private BankCard card; //structure public Add(BankCard card){ this.card = card; } @Override public void run() { for (int i = 0;i<10;i++){ card.save(1000); } } }
Sub
package Thread3; public class Sub implements Runnable{ private BankCard card; public Sub (BankCard card){ this.card = card; } @Override public void run() { for (int i = 0;i<10;i++){ card.take(1000); } } }
BankCard
package Thread3; public class BankCard { //balance private double money; //sign private boolean flag = false;//True means you can withdraw money if you have money, false means you can withdraw money if you have no money //save money public synchronized void save(double m){//Lock this if (flag) {//rich try { this.wait();//Enter the waiting queue, and the colleague releases the lock and cpu } catch (InterruptedException e) { e.printStackTrace(); } } money = money +m; System.out.println(Thread.currentThread().getName()+"Saved"+m+"The balance is"+money); //Modify tag flag = true; //Wake up the money withdrawal thread this.notify(); } //Withdraw money public synchronized void take(double m ){ if (!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } money = money - m; System.out.println(Thread.currentThread().getName()+"Yes"+m+"The balance is"+money); flag = false; //Wake up and save money this.notify(); } }
Test
package Thread3; public class TestBankCard { public static void main(String[] args) { //1 create a bank card BankCard card = new BankCard(); //2 create operation Add add = new Add(card); Sub sub = new Sub(card); //3 create thread object Thread chenchen = new Thread(add,"Morning morning"); Thread bingbing = new Thread(sub,"Bingbing"); //4 start chenchen.start(); bingbing.start(); } }
Analysis of multi storage capture problem
Will disorder
public class BankCard { //balance private double money; //sign private boolean flag = false;//True means you can withdraw money if you have money, false means you can withdraw money if you have no money //save money public synchronized void save(double m){//Lock this while (flag) {//If you have money, the default is true first? try { this.wait();//Enter the waiting queue, and the colleague releases the lock and cpu } catch (InterruptedException e) { e.printStackTrace(); } } money = money +m; System.out.println(Thread.currentThread().getName()+"Saved"+m+"The balance is"+money); //Modify tag flag = true; //Wake up the money withdrawal thread this.notify(); } //Withdraw money public synchronized void take(double m ){ while (!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } money = money - m; System.out.println(Thread.currentThread().getName()+"Yes"+m+"The balance is"+money); flag = false; //Wake up and save money this.notify(); } }
Replace if with while, which can be disordered
But it is also possible that all four threads are waiting
notify(); Change to notifyAll();
After all wakes up, whlie, the qualified ones enter the cycle
Problem solving
bounded-buffer problem
Producers and consumers:
Several producers are producing products, which will be provided to several consumers for consumption. In order to enable producers and consumers to execute concurrently, a buffer zone that can store multiple products is set between them. The producers put the produced products into the buffer zone, and consumers take the products from the buffer zone for consumption, Obviously, producers and consumers must keep synchronization, that is, consumers are not allowed to get products from an empty buffer, nor are producers allowed to put products into a full buffer.
Bread
package Thread3; public class Bread { private int id ; private String productName; public Bread(){ } public Bread(int id, String productName) { this.id = id; this.productName = productName; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getProductName() { return productName; } public void setProductName(String productName) { this.productName = productName; } @Override public String toString() { return "Bread{" + "id=" + id + ", productName='" + productName + '\'' + '}'; } }
Producer class
package Thread3; public class Product implements Runnable{ private BreadCon con; public Product(BreadCon con){ super(); this.con = con; } @Override public void run() { for (int i = 0;i<30;i++){ con.input(new Bread(i,Thread.currentThread().getName())); } } }
Consumer category
package Thread3; public class Consume implements Runnable{ private BreadCon con; public Consume(BreadCon con){ super(); this.con = con; } @Override public void run() { for (int i = 0;i < 30;i++){ con.output(); } } }
Bread containers
package Thread3; public class BreadCon { //An array of bread private Bread[] cons = new Bread[6]; //Where to store bread private int index = 0; public synchronized void input(Bread b){//Lock this //Judge whether the container is full while(index>=6){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } cons[index]=b; System.out.println(Thread.currentThread().getName()+"Produced"+b.getId()+""); index++; this.notifyAll(); } //Take out the bread public synchronized void output(){//Lock this while(index<=0){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } index--; Bread b = cons[index]; System.out.println(Thread.currentThread().getName()+"Consumption"+b.getId()+"producer"+b.getProductName()); cons[index] = null; //Wake up producers this.notifyAll(); } }
Test class
package Thread3; public class Test { public static void main(String[] args) { //container BreadCon con = new BreadCon(); //Production and consumption Product product = new Product(con); Consume consume = new Consume(con); //Create thread object Thread chenchen = new Thread(product,"Morning morning"); Thread bingbing = new Thread(consume,"consumption"); //Start thread chenchen.start(); bingbing.start(); } }