Thread communication
-
Example: print 1-100 using two threads. Thread 1 and thread 2 print alternately
-
package com.atguigu.java2; /** * Example of thread communication: use two threads to print 1-100, thread 1 and thread 2 to print alternately * * Three methods involved: * wait(): Once this method is executed, the current thread enters a blocking state and releases the synchronization monitor * notify(): Once this method is executed, a thread that is waiting will be awakened. If multiple threads are waiting, the one with the highest priority will be awakened * notifyAll(): Once this method is executed, all wait ing threads will be awakened * * explain: * 1.wait(),notify(),notifyAll()The three methods must be used in synchronous code blocks or synchronous methods * 2.wait(),notify(),notifyAll()The caller of the three methods must be the synchronization code block or the synchronization monitor in the synchronization method * Otherwise, an IllegalMonitorStateException will appear * 3.wait(),notify(),notifyAll()The three methods are defined in Java Lang. object class * * Interview question: what are the similarities and differences between sleep() and wait()? * 1.The same point: once the method is executed, the current thread can enter the blocking state * 2.difference: * 1)The positions of the two method declarations are different: sleep() is declared in the Thread class and wait() is declared in the Object class * 2)The requirements for calling are different: sleep () can be called in any required scenario. wait() must be used in a synchronization code block or synchronization method * 3)About whether to release the synchronization monitor: if both methods are used in the synchronization code block or synchronization method, sleep () will not release the lock, and wait () will release the lock * * @Author damao * @Date 2022/1/24 21:42 * @Version 1.0 */ class Number implements Runnable{ private int number = 1; @Override public void run() { while (true){ synchronized (this){ this.notify(); if (number <= 100){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":" + number); number++; try { //Make the thread calling the following wait() method enter the blocking state this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }else { break; } } } } } public class CommunicationTest { public static void main(String[] args) { Number number = new Number(); Thread t1 = new Thread(number); Thread t2 = new Thread(number); t1.setName("Thread 1"); t2.setName("Thread 2"); t1.start(); t2.start(); } }
wait() and notify() and notifyAll()
- wait(): suspend the current thread, abandon the CPU, synchronize resources and wait, so that other threads can access and modify shared resources. The current thread queues up for other threads to call notify() or notifyAll() method to wake up. After waking up, it can continue to execute after regaining ownership of the monitor
- notify(): wakes up the thread with the highest priority waiting for synchronization resources and ends the wait
- notifyAll(): wakes up all threads that are queuing for resources and ends waiting
- These three methods can only be used in synchronized methods or synchronized code blocks, otherwise they will report Java Lang.illegalmonitorstateexception
- Because these three methods must be called by a lock Object, and any Object can be used as a synchronized lock, these three methods can only be declared in the Object class
wait() method
- Call the method in the current thread: object name. wait()
- Make the current thread enter the state of waiting (an object) until another thread issues notify (or notifyAll) to the object
- Necessary condition for calling method: the current thread must have the right to monitor (lock) the object
- After calling this method, the current thread will release the object monitoring right and then enter the wait
- After the current thread is notified, you need to regain the monitoring right, and then continue the execution of the code from the breakpoint
notify()/notifyAll()
- Call the method in the current thread: object name. notify()
- Function: wake up one / all threads waiting for the monitoring right of the object
- Necessary condition for calling method: the current thread must have the right to monitor (lock) the object
producer consumer problem
-
The producer gives the product to the clerk, while the customer takes the product from the clerk. The clerk can only hold a fixed number of products at a time (e.g. 20). If the producer tries to produce more products, the clerk will ask the producer to stop. If there is an empty space in the store, the clerk will inform the producer to continue production; If there is no product in the store, the clerk will tell the consumer to wait. If there is a product in the store, the clerk will inform the consumer to take the product
-
There may be two problems:
- When producers are faster than consumers, consumers will miss some data
- When consumers are faster than producers, consumers will take the same data
-
package com.atguigu.java2; /** * Application of thread communication: classic example: Producer / consumer problem * * The producer gives the product to the clerk, and the customer takes the product from the clerk, * The clerk can only hold a fixed number of products at a time (e.g. 20). If the producer tries to produce more products, the clerk will * Will ask the producer to stop and inform the producer to continue production if there is a vacant place in the store; If there is no product in the store * If there is a product in the store, the clerk will tell the consumer to wait and inform the consumer to take the product. * * analysis: * 1. Is it a multithreading problem? Yes, producer thread, consumer thread * 2. Is there shared data? Yes, clerk (or product) * 3. How to solve the thread safety problem? Synchronization mechanism, there are three methods * 4. Is thread communication involved? yes * * @author damao * @create 2022-01-25 21:48 PM */ class Clerk{ private int productCount = 0; //yield a product public synchronized void produceProduct() { if(productCount < 20){ productCount++; System.out.println(Thread.currentThread().getName() + ":Start production" + productCount + "Products"); notify(); }else{ //wait for try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } //Consumer products public synchronized void consumeProduct() { if(productCount > 0){ System.out.println(Thread.currentThread().getName() + ":Start consumption" + productCount + "Products"); productCount--; notify(); }else{ //wait for try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Producer extends Thread{//producer private Clerk clerk; public Producer(Clerk clerk) { this.clerk = clerk; } @Override public void run() { System.out.println(getName() + ":Start production....."); while(true){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } clerk.produceProduct(); } } } class Consumer extends Thread{//consumer private Clerk clerk; public Consumer(Clerk clerk) { this.clerk = clerk; } @Override public void run() { System.out.println(getName() + ":Start consuming products....."); while(true){ try { Thread.sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } clerk.consumeProduct(); } } } public class ProductTest { public static void main(String[] args) { Clerk clerk = new Clerk(); Producer p1 = new Producer(clerk); p1.setName("Producer 1"); Consumer c1 = new Consumer(clerk); c1.setName("Consumer 1"); Consumer c2 = new Consumer(clerk); c2.setName("Consumer 2"); p1.start(); c1.start(); c2.start(); } }
JDK5.0 new thread creation method
-
New method 1: implement Callable interface
-
Callable is more powerful than Runnable
- Compared with the run () method, it can have a return value
- Method can throw an exception
- Return values that support generics
- You need to use the FutureTask class to get the returned results, for example
-
Future interface
- You can cancel the execution results of specific Runnable and Callable tasks, query whether they are completed, obtain results, etc
- FutureTask is the only implementation class of the Future interface
- FutureTask implements both Runnable and Future interfaces. It can be executed by the thread as Runnable or get the return value of Callable as Future
-
package com.atguigu.java2; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * The third way to create a thread is to implement the Callable interface-- JDK5.0 NEW * * How to understand that the method of implementing Callable interface to create multithreading is more powerful than that of implementing Runnable interface to create multithreading? * 1.call()Can have return value * 2.call()Exceptions can be thrown and captured by external operations to obtain exception information * 3.Callable It supports generics * * @Author damao * @Date 2022/1/26 22:02 * @Version 1.0 */ //1. Create an implementation class that implements Callable class NumThread implements Callable{ //2. Implement the call method and declare the operation to be performed by this thread in call() @Override public Object call() throws Exception { int sum = 0; for (int i = 1; i <= 100; i++) { if (i%2==0){ System.out.println(i); sum += i; } } return sum; } } public class ThreadNew { public static void main(String[] args) { //3. Create an object of the Callable interface implementation class NumThread numThread = new NumThread(); //4. Pass the object of this Callable interface implementation class to the FutureTask constructor as a and create the object of FutureTask FutureTask futureTask = new FutureTask(numThread); //5. Pass the FutureTask object as a parameter to the constructor of the Thread class, create the Thread object, and call start() new Thread(futureTask).start(); try { //6. Get the return value of call method in Callable //The return value of the get() method is the return value of the call() method overridden by the FutureTask constructor parameter Callable object Object sum = futureTask.get(); System.out.println("The sum is:" + sum); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
-
New method 2: 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. Similar to public transport in life
-
Benefits:
- Improved response speed (reduced time to create new threads)
- Reduce resource consumption (reuse threads in the thread pool and do not need to be created every time)
- Easy thread management
- corePoolSize: the size of the core pool
- maximumPoolSize: maximum number of threads
- keepAliveTime: how long will the thread terminate without a task
-
package com.atguigu.java2; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; /** * Four ways to create threads: using thread pool * * Benefits: * 1.Improved response speed (reduced time to create new threads) * 2.Reduce resource consumption (reuse threads in the thread pool and do not need to be created every time) * 3.Easy thread management * corePoolSize: Size of core pool * maximumPoolSize: Maximum number of threads * keepAliveTime: The thread has no task. How long does it last at most and then it will terminate * * Interview question: how many ways to create multithreading? Four! * @Author damao * @Date 2022/1/27 21:02 * @Version 1.0 */ class NumberThread implements Runnable{ @Override public void run() { for (int i = 0; i <= 100; i++) { if (i % 2 == 0){ System.out.println(Thread.currentThread().getName() + ":" + i); } } } } class NumberThread1 implements Runnable{ @Override public void run() { for (int i = 0; i <= 100; i++) { if (i % 2 != 0){ System.out.println(Thread.currentThread().getName() + ":" + i); } } } } public class ThreadPool { public static void main(String[] args) { //1. Provide a thread pool with a specified number of threads ExecutorService service = Executors.newFixedThreadPool(10); ThreadPoolExecutor service1 = (ThreadPoolExecutor) service; //Set properties of thread pool // System.out.println(service.getClass()); service1.setCorePoolSize(15); // service1.setKeepAliveTime(); //2. To execute the operation of the specified thread, you need to provide an object that implements the Runnable interface or Callable interface implementation class service.execute(new NumberThread());//Suitable for Runnable service.execute(new NumberThread1());//Suitable for Runnable // service.submit(Callable callable);// Suitable for callable //3. Close the connection pool service.shutdown(); } }
Thread pool related API
- JDK5. Thread pool related API s: ExecutorService and Executors have been provided since 0
- 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 is generally executed again
- void shutdown(): closes the connection pool
- Executors: tool class and factory class of thread pool, which are used to create and return different types of thread pools
- Executors.newCachedThreadPool(): create a thread pool that can create new threads as needed
- Executors.newFixedThreadPool(n); Create a reusable thread pool with a fixed number of threads
- Executors.newSingleThreadExecutor(): create a thread pool with only one thread
- Executors.newScheduledThreadPool(n): creates a thread pool that can schedule commands to run after a given delay or execute periodically