This chapter mainly clarifies multithreading
Processes and threads
- Process is the unit of system resource allocation, and thread is the unit of CPU scheduling and execution
There are three ways to create threads
Inherit Thread class (not recommended to avoid the limitation of OOP single inheritance)
- The custom Thread class inherits the Thread class
- Rewrite the run() method to write the thread execution body
- Create a thread object and call the start() method to start the thread
public class ThreadTest extends Thread{ //Thread entry point @Override public void run(){ //Thread body for (int i = 1; i <= 5; i++) { System.out.println("Already implemented"+i+"second"); } } public static void main(String[] args) { //Create thread object ThreadTest threadTest=new ThreadTest(); threadTest.start(); } } //Output results: Executed for 1 second It has been executed for 2 seconds It has been executed for 3 seconds It has been executed for 4 seconds It has been executed for 5 seconds
Case: download pictures
public class ThreadTest extends Thread{ private String url; private String name; public ThreadTest(String url, String name) { this.url = url; this.name = name; } @Override public void run(){ WebDownloader webDownloader=new WebDownloader(); try { webDownloader.downloader(url,name); System.out.println("This file has been downloaded:"+name); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { ThreadTest t1=new ThreadTest("https://cdn.jsdelivr.net/gh/jasper807/picgo/cover/javaio.png","src/img/p1.png"); ThreadTest t2=new ThreadTest("https://cdn.jsdelivr.net/gh/jasper807/picgo/cover/javaio.png","src/img/p2.png"); ThreadTest t3=new ThreadTest("https://cdn.jsdelivr.net/gh/jasper807/picgo/cover/javaio.png","src/img/p3.png"); //Start thread t1.start(); t2.start(); t3.start(); } } //File download tool class class WebDownloader{ //Remote path, storage name public void downloader(String url,String name) throws IOException { FileUtils.copyURLToFile(new URL(url),new File(name)); } } //Output results: This file has been downloaded: src/img/p3.png This file has been downloaded: src/img/p2.png This file has been downloaded: src/img/p1.png
Implement the Runnable interface (recommended to facilitate the use of the same object by multiple threads)
- The custom thread class implements the Runnable interface
- Implement the run() method and write the thread execution body
- New thread (pass in the target object) start()
public class RunnableTest implements Runnable{ @Override public void run() { for (int i = 1; i <= 5; i++) { System.out.println("Already implemented"+i+"second"); } } public static void main(String[] args) { new Thread(new RunnableTest()).start(); } } //Output results: Executed for 1 second It has been executed for 2 seconds It has been executed for 3 seconds It has been executed for 4 seconds It has been executed for 5 seconds
Case: download pictures
public class RunnableTest implements Runnable{ private String url; private String name; public RunnableTest(String url, String name) { this.url = url; this.name = name; } @Override public void run() { WebDownloader webDownloader=new WebDownloader(); try { webDownloader.downloader(url,name); System.out.println("This file has been downloaded:"+name); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { new Thread(new ThreadTest("https://cdn.jsdelivr.net/gh/jasper807/picgo/cover/javaio.png","src/img/p1.png")).start(); new Thread(new ThreadTest("https://cdn.jsdelivr.net/gh/jasper807/picgo/cover/javaio.png","src/img/p2.png")).start(); new Thread(new ThreadTest("https://cdn.jsdelivr.net/gh/jasper807/picgo/cover/javaio.png","src/img/p3.png")).start(); } } //Output results: This file has been downloaded: src/img/p3.png This file has been downloaded: src/img/p1.png This file has been downloaded: src/img/p2.png
Implement Callable interface (just understand)
- 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 executorservice executorservice = executors newFixedThreadPool(1);
- Submit and execute future < Boolean > result1 = Ser submit(t1);
- Get the result Boolean R1 = result1 get();
- Close the service Ser shutdownNow();
public class CallableTest implements Callable<Boolean> { private String url; private String name; public CallableTest(String url, String name) { this.url = url; this.name = name; } @Override public Boolean call() throws Exception { WebDownloader webDownloader=new WebDownloader(); try { webDownloader.downloader(url,name); System.out.println("This file has been downloaded:"+name); } catch (IOException e) { e.printStackTrace(); } return true; } public static void main(String[] args) { CallableTest t1=new CallableTest("https://cdn.jsdelivr.net/gh/jasper807/picgo/cover/javaio.png","src/img/p1.png"); CallableTest t2=new CallableTest("https://cdn.jsdelivr.net/gh/jasper807/picgo/cover/javaio.png","src/img/p2.png"); CallableTest t3=new CallableTest("https://cdn.jsdelivr.net/gh/jasper807/picgo/cover/javaio.png","src/img/p3.png"); //Create execution service ExecutorService ex= Executors.newFixedThreadPool(3); //Submit for execution Future<Boolean> result1= (Future<Boolean>) ex.submit(t1); Future<Boolean> result2= (Future<Boolean>) ex.submit(t2); Future<Boolean> result3= (Future<Boolean>) ex.submit(t3); //Get results try{ if (result1.get()!=null){ boolean r1= result1.get(); System.out.println("r1="+r1); } if (result2.get()!=null){ boolean r2= result2.get(); System.out.println("r2="+r2); } if (result3.get()!=null){ boolean r3= result3.get(); System.out.println("r3="+r3); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } //Shut down service ex.shutdownNow(); } } //Output results: This file has been downloaded: src/img/p1.png This file has been downloaded: src/img/p3.png r1=true This file has been downloaded: src/img/p2.png r2=true r3=true
Case: Tortoise rabbit race
public class Race implements Runnable{ //winner private static String winner; @Override public void run() { for (int i = 1; i <= 20; i++) { //Simulated rabbit rest if (Thread.currentThread().getName().equals("rabbit")&&i%5==0){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } boolean flag=gameOver(i); if (flag){ break; } System.out.println(Thread.currentThread().getName()+ "--->Run away"+i+"step"); } } //Judge whether to complete the game public boolean gameOver(int steps){ //Judge whether there is a winner if (winner!=null){ return true; } if (steps>=20){ 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(); } } //Output results: rabbit--->Took a step rabbit--->Ran two steps rabbit--->Three steps rabbit--->Four steps tortoise--->Took a step tortoise--->Ran two steps tortoise--->Three steps tortoise--->Four steps tortoise--->Five steps tortoise--->Six steps tortoise--->Seven steps tortoise--->Eight steps tortoise--->Nine steps tortoise--->Ten steps tortoise--->Ran 11 steps tortoise--->12 steps tortoise--->13 steps tortoise--->Ran 14 steps tortoise--->Ran 15 steps tortoise--->16 steps tortoise--->17 steps tortoise--->Ran 18 steps tortoise--->Ran 19 steps winner is tortoise
Static proxy
public class StaticProxy { public static void main(String[] args) { //This marriage case is equivalent to simulating thread static agent, which is equivalent to the following new WeddingCompany(new Man()).getMarry(); new Thread(new Runnable() { @Override public void run() { } }); } } interface Marry{ void getMarry(); } //Real role class Man implements Marry{ @Override public void getMarry() { System.out.println("Marry..."); } } //delegable role class WeddingCompany implements Marry{ private Marry target; public WeddingCompany(Marry target) { this.target = target; } @Override public void getMarry() { before(); target.getMarry(); after(); } private void before(){ System.out.println("Before..."); } private void after(){ System.out.println("After..."); } } //Output results: Before... Marry... After...
Lambda expression
Functional interface
- Any excuse that contains only one abstract method is a functional interface
- For functional interfaces, we can create the interface object through Lambda expressions
Evolution of Lambda expressions
Create object call method
public class LambdaTest { public static void main(String[] args) { Tom tom=new Tom(); tom.eatApple(3); } } interface Apple{ void eatApple(int num); } class Tom implements Apple{ @Override public void eatApple(int num) { System.out.println("Tom Yes"+ num + "An apple"); } } //Output results: Tom Ate three apples
Static inner class
public class LambdaTest { //Static inner class static class Tom implements Apple{ @Override public void eatApple(int num) { System.out.println("Tom Yes"+ num + "An apple"); } } public static void main(String[] args) { Tom tom=new Tom(); tom.eatApple(3); } } interface Apple{ void eatApple(int num); } //Output results: Tom Ate three apples
Local inner class
public class LambdaTest { public static void main(String[] args) { //Local inner class class Tom implements Apple{ @Override public void eatApple(int num) { System.out.println("Tom Yes"+ num + "An apple"); } } Tom tom=new Tom(); tom.eatApple(3); } } interface Apple{ void eatApple(int num); } //Output results: Tom Ate three apples
Anonymous Inner Class
public class LambdaTest { public static void main(String[] args) { Apple tomEatApple=new Apple() { @Override public void eatApple(int num) { System.out.println("Tom Yes"+ num + "An apple"); } }; tomEatApple.eatApple(3); } } interface Apple{ void eatApple(int num); } //Output results: Tom Ate three apples
Change to Lamda expression
- Lambda expressions can only be simplified into one line when there is only one line of code. If there are multiple lines, they are wrapped in code blocks
- The premise of Lambda expression is that the interface is functional
- You can only remove the parameter type of multiple parameters. If you want to remove them, you must remove them all and add parentheses
public class LambdaTest { public static void main(String[] args) { Apple tomEatApple=(int num)-> { System.out.println("Tom Yes"+ num + "An apple"); }; //Simplified parameter type tomEatApple=(num)-> { System.out.println("Tom Yes"+ num + "An apple"); }; //Simplified parentheses tomEatApple=num-> { System.out.println("Tom Yes"+ num + "An apple"); }; //Simplified curly braces tomEatApple=num-> System.out.println("Tom Yes"+ num + "An apple"); tomEatApple.eatApple(3); } } interface Apple{ void eatApple(int num); } //Output results: Tom Ate three apples
Thread state
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 will be terminated
public class StopTest implements Runnable{ private boolean flag=true; @Override public void run() { while(flag){ System.out.println("run..."); } } public void stop(){ this.flag=false; } public static void main(String[] args) throws InterruptedException { StopTest stopTest = new StopTest(); new Thread(stopTest).start(); for (int i = 1; i <= 10; i++) { System.out.println("main"+i); if (i==5){ stopTest.stop(); System.out.println("run The thread is about to stop"); } } } } //Output results: main1 main2 main3 main4 main5 run... run The thread is about to stop main6 main7 main8 main9 main10
Thread sleep
- Each object has a lock, and sleep will not release the lock
public class SleepTest { //1. Analog delay //2. Print the current system time public static void getNowTime() throws InterruptedException { Date startTime=new Date(System.currentTimeMillis()); for (int i = 0; i < 5; i++) { Thread.sleep(1000); System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime)); startTime=new Date(System.currentTimeMillis()); } } //3. Analog countdown public static void timeDown() throws InterruptedException { int num=5; while (true){ Thread.sleep(1000); System.out.println(num--); if (num<=0){ break; } } } public static void main(String[] args) throws InterruptedException { getNowTime(); System.out.println("---"); timeDown(); } } //Output results: 11:10:44 11:10:45 11:10:46 11:10:47 11:10:48 --- 5 4 3 2 1
Thread yield
//Source code /** * A hint to the scheduler that the current thread is willing to yield * its current use of a processor. The scheduler is free to ignore this * hint. * * <p> Yield is a heuristic attempt to improve relative progression * between threads that would otherwise over-utilise a CPU. Its use * should be combined with detailed profiling and benchmarking to * ensure that it actually has the desired effect. * * <p> It is rarely appropriate to use this method. It may be useful * for debugging or testing purposes, where it may help to reproduce * bugs due to race conditions. It may also be useful when designing * concurrency control constructs such as the ones in the * {@link java.util.concurrent.locks} package. */ public static native void yield();
- When calling thread When yield (), it will give the thread scheduler a hint that the current thread is willing to sell CPU usage, but the thread scheduler may ignore this hint
public class YieldTest implements Runnable{ public static void main(String[] args) { YieldTest yieldTest=new YieldTest(); new Thread(yieldTest,"A").start(); new Thread(yieldTest,"B").start(); } @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println("Current thread is: "+ Thread.currentThread().getName()+ i); if (i == 3){ Thread.yield(); } } } } //Output results: //Case 1: after B3, give up the CPU, AB threads compete at the same time, and A obtains the CPU. Comity succeeds Current thread is: B0 Current thread is: B1 Current thread is: B2 Current thread is: B3 Current thread is: A0 Current thread is: A1 Current thread is: A2 Current thread is: A3 Current thread is: A4 Current thread is: B4 //In case 2, A3 gives up the CPU, AB threads compete at the same time, and a obtains the CPU without comity Current thread is: A0 Current thread is: A1 Current thread is: A2 Current thread is: A3 Current thread is: A4 Current thread is: B0 Current thread is: B1 Current thread is: B2 Current thread is: B3 Current thread is: B4
Thread enforces join
public class JoinTest implements Runnable{ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("vip"+i+"..."); } } public static void main(String[] args) throws InterruptedException { Thread thread=new Thread(new JoinTest()); thread.start(); for (int i = 0; i < 10; i++) { System.out.println("main"+i+"..."); if (i==2){ thread.join(); } } } } //Output results: main0... main1... main2... vip0... vip1... vip2... vip3... vip4... vip5... vip6... vip7... vip8... vip9... main3... main4... main5... main6... main7... main8... main9...
Observe thread status
-
New: a new thread object is created, but the start() method has not been called yet
-
Runnable: the two states of ready and running in Java threads are generally called "running". After the thread object is created, other threads (such as the main thread) call the start() method of the object. The thread in this state is located in the runnable thread pool, waiting to be selected by thread scheduling to obtain the use right of CPU. At this time, it is in ready state. A thread in the ready state becomes running after obtaining the CPU time slice
-
Blocked: indicates that the thread is blocked in a lock
-
Waiting: the thread entering this state needs to wait for other threads to make some specific actions (notification or interrupt)
-
Terminated: indicates that the thread has completed execution
public class StateTest { public static void main(String[] args) throws InterruptedException { Thread thread=new Thread(()->{ for (int i = 0; i < 3; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("In operation..."); } }); Thread.State state=thread.getState(); //NEW System.out.println(state); //RUNNABLE thread.start(); state=thread.getState(); System.out.println(state); //TERMINATED while (state!= Thread.State.TERMINATED){ Thread.sleep(100); state=thread.getState(); System.out.println(state); } } } //Operation results: NEW RUNNABLE TIMED_WAITING In operation... TIMED_WAITING In operation... TIMED_WAITING In operation... TERMINATED
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
- 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 CPU scheduling
- Thread.MIN_PRIORITY = 1; Thread.MAX_PRIORITY = 10; Thread.NORM_PRIORITY = 5
public class PriorityTest implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()); } public static void main(String[] args) { //Main thread priority System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()); PriorityTest p=new PriorityTest(); Thread t1 = new Thread(p); Thread t2 = new Thread(p); Thread t3 = new Thread(p); Thread t4 = new Thread(p); Thread t5 = new Thread(p); //Set priority before starting t1.start(); t2.setPriority(Thread.MAX_PRIORITY); t2.start(); t3.setPriority(Thread.MIN_PRIORITY); t3.start(); t4.setPriority(7); t4.start(); t5.setPriority(3); t5.start(); } } //Output results: main:5 Thread-1:10 Thread-4:3 Thread-3:7 Thread-2:1 Thread-0:5
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 complete execution, such as recording operation logs in the background, monitoring memory, garbage collection and so on
public class DaemonTest { public static void main(String[] args) { God god=new God(); You you=new You(); Thread thread=new Thread(god); thread.setDaemon(true);//By default, false is the user thread, and normal threads are user threads thread.start(); new Thread(you).start(); } } class God implements Runnable{ @Override public void run() { while (true){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Guard you..."); } } } class You implements Runnable{ @Override public void run() { for (int i = 0; i < 10; i++) { if (i%3==0){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("In life..."); } System.out.println("End of life..."); } } //Output results: In life... In life... In life... Guard you... In life... In life... In life... Guard you... In life... In life... In life... Guard you... In life... End of life... Guard you...
Thread synchronization
-
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 want to modify the object. At this time, we need thread synchronization. Thread synchronization is actually 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 use it, and then use it again for the next thread.
-
Because 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, 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-threaded competition, locking and releasing locks will lead to more context switching and scheduling delays, resulting in performance problems
- If a high priority thread waits for a low priority thread to release the lock, it will lead to priority inversion and performance problems
Synchronization method
public synchronized void method(int args) {}
- Synchronized methods control access to "objects". Each object corresponds to a lock. Each synchronized method must obtain the lock of the object calling the method before execution, otherwise the thread will block. Once the method is executed, it will monopolize the lock until the method returns, and the lock will not be released until the blocked thread can obtain the lock and continue to execute.
Case: queuing to buy tickets
public class BuyTicket{ public static void main(String[] args) { Ticket ticket=new Ticket(); new Thread(ticket,"User 1").start(); new Thread(ticket,"User 2").start(); new Thread(ticket,"User 3").start(); } } class Ticket implements Runnable{ private int ticketNums=10; boolean flag= true; @Override public void run() { while (flag){ try { Thread.sleep(1000); buy(); } catch (InterruptedException e) { e.printStackTrace(); } } } private synchronized void buy() { if (ticketNums<=0){ flag=false; return; } System.out.println(Thread.currentThread().getName()+"Bought a second"+(10-ticketNums+1)+"Ticket"); ticketNums--; } } //Output results: User 1 bought the first ticket User 2 bought the second ticket User 3 bought the third ticket User 1 bought the 4th ticket User 2 bought the fifth ticket User 3 bought the sixth ticket User 1 bought the 7th ticket User 2 bought the 8th ticket User 3 bought the 9th ticket User 1 bought the 10th ticket
Synchronization block
synchronized (Obj obj) {}
-
Obj is called synchronization monitor. OBJ can be 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
Case: bank withdrawal
public class GoBank { public static void main(String[] args) { Account account=new Account("Marry Money",100); Drawing dad=new Drawing(account,50,"dad"); Drawing mom=new Drawing(account,100,"mom"); dad.start(); mom.start(); } } //account class Account{ private String cardName;//Card name private int money;//balance public Account(String cardName, int money) { this.cardName = cardName; this.money = money; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } public String getCardName() { return cardName; } public void setCardName(String cardName) { this.cardName = cardName; } } //bank class Drawing extends Thread{ private Account account; private int drawingMoney; private int nowMoney; private String name; public Drawing(Account account, int drawingMoney, String name) { this.account = account; this.drawingMoney = drawingMoney; this.name=name; } public void run(){ synchronized (account){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //Judge whether there is money if (account.getMoney()-drawingMoney<0){ System.out.println(name+"The money is not enough"); return; } System.out.println(account.getCardName()+"by"+account.getMoney()); account.setMoney(account.getMoney()-drawingMoney); nowMoney=nowMoney+drawingMoney; //Thread.currentThread().getName()=this.getName() System.out.println(name+"Money in hand"+nowMoney); System.out.println(account.getCardName()+"The balance is"+account.getMoney()); } } } //Output results: Marry Money Is 100 dad Money in hand 50 Marry Money The balance is 50 mom The money is not enough
Case: Security collection
//Method 1 public class SafeList { 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); System.out.println(list.size()); } } //Output results: 10000 //Method 2 uses a set of security types designed by the system public class SafeList { public static void main(String[] args) throws InterruptedException { CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<>(); for (int i = 0; i < 10000; i++) { new Thread(()-> { list.add(Thread.currentThread().getName()); }).start(); } Thread.sleep(3000); System.out.println(list.size()); } } //Output results: 10000
What is the lock object in the synchronization method or synchronization code block
- For normal synchronization methods, the lock is the current instance object
- For static synchronization methods, the lock is the Class object of the current Class
- For synchronized method blocks, locks are objects configured in synchronized parentheses
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. Deadlock may occur when a synchronization block has locks of more than two objects at the same time.
Case: lipstick and mirror
public class DeadLock { public static void main(String[] args) { MakeUp girl1=new MakeUp(0,"girl1"); MakeUp girl2=new MakeUp(1,"girl2"); girl1.start(); girl2.start(); } } //Lipstick class LipStick{ } //mirror class Mirror{ } class MakeUp extends Thread{ //static keyword to ensure a static LipStick lipStick=new LipStick(); static Mirror mirror=new Mirror(); int choice; String girlName; public MakeUp(int choice, String girlName) { this.choice = choice; this.girlName = girlName; } public void run(){ //Make up try { makeUp(); } catch (InterruptedException e) { e.printStackTrace(); } } private void makeUp() throws InterruptedException { if (choice==0){ //Get lipstick lock synchronized (lipStick){ System.out.println(girlName+"Get lipstick lock"); Thread.sleep(1000); //Get the lock of the mirror synchronized (mirror){ System.out.println(girlName+"Get the lock of the mirror"); } } }else if (choice==1){ //Get the lock of the mirror synchronized (mirror){ System.out.println(girlName+"Get the lock of the mirror"); Thread.sleep(2000); //Get lipstick lock synchronized (lipStick){ System.out.println(girlName+"Get lipstick lock"); } } } } } //Output result: they all want to get each other's lock, resulting in being stuck here all the time girl1 Get lipstick lock girl2 Get the lock of the mirror
Lock lock
- If there is an exception in the synchronization block, write unlock() to the finally statement block
Case: queuing to buy tickets
public class LockTest { public static void main(String[] args) { Ticket2 ticket=new Ticket2(); new Thread(ticket,"User 1").start(); new Thread(ticket,"User 2").start(); new Thread(ticket,"User 3").start(); } } class Ticket2 implements Runnable{ //Define lock lock private final ReentrantLock lock=new ReentrantLock(); private int ticketNums=10; boolean flag= true; @Override public void run() { while (flag){ try { Thread.sleep(1000); //Lock lock.lock(); buy(); } catch (InterruptedException e) { e.printStackTrace(); }finally { //Unlock lock.unlock(); } } } private void buy() { if (ticketNums<=0){ flag=false; return; } System.out.println(Thread.currentThread().getName()+"Bought a second"+(10-ticketNums+1)+"Ticket"); ticketNums--; } } //Output result: analog synchronization method
Thread collaboration producer consumer model
- Producers and consumers share the same resource, and producers and consumers are interdependent and conditional on each other
- Java provides several methods to solve the communication problem between threads:
- wait() 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() wakes up a waiting thread
- notifyAll() wakes up all threads calling the wait() method on the same object. Threads with higher priority are scheduled first
- All methods of Object class can only be used in synchronization methods or synchronization code blocks, otherwise an exception IllegalMonitorStateException will be thrown
Pipe pass method using buffer zone
public class PCTest { public static void main(String[] args) throws InterruptedException { 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; } public void run(){ for (int i = 1; i <= 10; i++) { try { container.push(new Chicken(i)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Produced the second"+i+"Chicken"); } } } //consumer class Consumer extends Thread{ SynContainer container; public Consumer(SynContainer container) { this.container = container; } public void run(){ for (int i = 1; i <= 10; i++) { try { System.out.println("Consumed the second"+container.pop().id+"Chicken"); Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } //product class Chicken{ int id; public Chicken(int id) { this.id = id; } } //buffer class SynContainer{ //A container size is required, that is, the buffer can only hold five chickens. Although the producer produces chickens again, they will be blocked later Chicken[] chickens=new Chicken[5]; //Container counter int count=0; //The producer puts in the product public synchronized void push(Chicken chicken) throws InterruptedException { while (count==chickens.length){ wait();//Producer waiting } //If it is not full, throw it into the product chickens[count]=chicken; count++; //Inform consumers of consumption notifyAll(); } //Consumer products public synchronized Chicken pop() throws InterruptedException { Chicken thisChicken=null; //Judge whether it can be consumed while (count==0){ wait();//Consumer waiting } //If you can consume count--; thisChicken = chickens[count]; //When finished, inform the producer to produce notifyAll(); return thisChicken; } } //Output results: The first chicken was produced A second chicken was produced A third chicken was produced The fourth chicken was produced The fifth chicken was produced The fifth chicken was consumed The sixth chicken was produced The seventh chicken was produced Consumed the sixth chicken The eighth chicken was produced Consumed the seventh chicken Consumed the 8th chicken The ninth chicken was produced The 9th chicken was consumed The 10th chicken was produced Consumed the 10th chicken The fourth chicken was consumed Consumed the third chicken Consumed the second chicken Consumed the first chicken
Sign bit used by signal lamp method
public class PCTest2 { public static void main(String[] args) { TV tv=new TV(); new Player(tv).start(); new Watcher(tv).start(); } } //Producer actor class Player extends Thread{ TV tv; public Player(TV tv) { this.tv = tv; } public void run(){ for (int i = 0; i < 5; i++) { if (i%2==0){ try { tv.play("Program 1"); } catch (InterruptedException e) { e.printStackTrace(); } }else { try { tv.play("Program 2"); } catch (InterruptedException e) { e.printStackTrace(); } } } } } //Consumer audience class Watcher extends Thread{ TV tv; public Watcher(TV tv) { this.tv = tv; } public void run(){ for (int i = 0; i < 5; i++) { try { Thread.sleep(300); tv.watch(); } catch (InterruptedException e) { e.printStackTrace(); } } } } //Product program class TV{ String voice; boolean flag=true; //perform public synchronized void play(String voice) throws InterruptedException { if (!flag){ wait(); } System.out.println("The actors performed:"+voice); //Inform the audience to watch notifyAll(); this.voice=voice; this.flag=!this.flag; } //watch public synchronized void watch() throws InterruptedException{ if (flag){ wait(); } System.out.println("Watched:"+voice); //Inform the actors to perform notifyAll(); this.flag=!this.flag; } } //Output results: The actors performed: Program 1 Watched: Program 1 The actor performed: program 2 Watched: program 2 The actors performed: Program 1 Watched: Program 1 The actor performed: program 2 Watched: program 2 The actors performed: Program 1 Watched: Program 1
Thread pool
-
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
- < T > Future < T > submit (Callable < T > task): when a task is executed, it has a return value. Generally, Callable is executed again
- void shutdown(): closes the connection pool
-
Executors: tool class and thread pool factory class, which are used to create and return different types of thread pools
//Taking the Runnable interface of the test thread pool as an example, Callable is mentioned above public class PoolTest { public static void main(String[] args) { //Create service, create thread pool ExecutorService ex= Executors.newFixedThreadPool(2); //implement ex.execute(new MyThread()); ex.execute(new MyThread()); //Close connection ex.shutdown(); } } class MyThread implements Runnable{ @Override public void run() { for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName()+" "+i); } } } //Output results: pool-1-thread-1 0 pool-1-thread-1 1 pool-1-thread-1 2 pool-1-thread-2 0 pool-1-thread-2 1 pool-1-thread-2 2
Hi, welcome to JasperのBlog!