preface
This article refers to the Silicon Valley Java tutorial
Continue to update the Java advanced section in the future
General catalogue
1, Basic concepts
1. Procedure
It is a set of instructions written in a certain language to complete characteristic tasks. That is, static code, static objects
2. Process
A process is an execution of a program, or a running program. It is a dynamic process with its own process of emergence, existence and extinction - life cycle
Such as QQ in operation and LOL in operation
The program is static and the process is dynamic
Process is the unit of resource allocation. The system will allocate different memory areas for each process at run time
3. Thread
A process can be subdivided into threads, which is an execution path within a program
If a process executes multiple threads in parallel at the same time, it supports multithreading
Thread is the unit of scheduling and execution. Each thread uses an independent running stack and program counter (pc). The overhead of thread switching is small
Multiple threads in a process share the same memory unit / memory address space. They allocate objects from the same heap and can access the same variables and objects. This makes the communication between threads easier and more efficient. However, system resources shared by multiple threads may bring security risks
Memory structure of JVM virtual machine
3. Case understanding
The above figure shows the processes running on my computer. The running software (a set of instructions written to complete characteristic tasks) is a process (an execution process of the program). For example, my IDEA can open multiple windows, that is, the IDEA supports threads (an execution path inside the program)
4. Understanding of single core CPU and multi-core CPU
Single core CPU is a fake multithreading. In a time unit, only one thread can be executed, but the CPU runs faster and can't feel it.
If it is multi-core, it can give better play to the efficiency of multithreading. (today's servers are multi-core)
A Java application java.exe actually has at least three threads: Main () main thread, gc () garbage collection thread and exception handling thread
5. Parallelism and concurrency
Parallel: multiple CPU s execute multiple tasks at the same time. For example, many people do different things at the same time.
Concurrency: one CPU (using time slice) executes multiple tasks at the same time. For example: Double 11 second kill, multiple people do the same thing.
6. Advantages of using multithreading
1. Improve application response. It is more interesting for the graphical interface and can enhance the user experience
2. Improve CPU utilization of computer system
3. Improve the program structure. The long and complex process is divided into multiple threads, which is allowed in the calf, which is conducive to understanding and modification
7. When multithreading is required
The program needs to perform two or more tasks at the same time
The program needs to be implemented -- when some tasks need to wait, such as user input, file read-write operation, network operation, search, etc
When you need some programs running in the background
2, Creation and use of threads
The JVM of the Java language allows programs to run multiple threads, which is embodied by the java.lang.Thread class.
1. Characteristics of thread class
Each Thread completes its operation through the run() method of a specific Thread object. The body of the run() method is often called the Thread body
Start the Thread through the start() method of the Thread object instead of directly calling run()
2.Thread class
constructor
Thread(): creates a new thread object
Thread(String threadname): create a thread and specify the thread instance name
Thread(Runnable target): Specifies the target object to create the thread, which implements the run method in the Runnable interface
Thread(Runnable target, String name): creates a new thread object
3. There are two ways to create threads in API
There are two ways to create a new execution thread before JDK15:
How to inherit the Thread class
How to implement the Runnable interface
Method 1: inherit Thread class
1) Defines subclasses that inherit the Thread class
2) Override the run method in the Thread class in the subclass.
3) Create a Thread subclass object, that is, create a Thread object.
4) Call the thread object start method: start the thread and call the run method.
package com.example.www.d4; /** * @ClassName ThreadTest * @Description Multithreading practice * @Author Jack * @Date 2021/11/21 20:58 * @Version 1.0 */ /** * Multi Thread creation: Method 1: inherit from Thread class * 1,Create a subclass that inherits the Thread class * 2,Override the run () method of the tree class -- > declare the operation performed by this thread in the method body * 3,An object that creates a subclass of the Thread class * 4,start() is called from this object * <p> * Example: traverse all even numbers within 100 */ //1. Create a subclass that inherits Thread class class MyThread extends Thread { //2. Rewrite the run method @Override public void run() { for (int i = 0; i < 101; i++) { if (i % 2 == 0) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } } public class ThreadTest { public static void main(String[] args) { //3. Create objects of subclasses of Thread class MyThread t1 = new MyThread(); //4. Call start() through this object t1.start();//Cause this thread to start execution; The Java virtual machine calls the run method of this thread. //Problem 1: we can't start the thread by calling the run method // myThread.run(); // No new threads will be started //Problem 2: start another thread and traverse an even number within 100. You can't let the thread that has started () execute. An illegalThread exception will be reported //We need to recreate a Thread object, that is, recreate an object of Thread subclass MyThread t2 = new MyThread(); t2.start(); //The following operations are still performed in the main thread for (int i = 0; i < 101; i++) { if (i % 2 != 0) { System.out.println(Thread.currentThread().getName() + "" + "**********hello********"); } } } }
The implementation is as follows:
Attention
1. If you call the run() method manually, it's just a normal method and does not start the multithreading mode.
2. The run () method is called by the JVM. When it is called and the process control executed are determined by the CPU scheduling of the operating system.
3. To start multithreading, you must call the start method.
4. A thread object can only call the start() method once to start. If it is called repeatedly, the above exception "lllgalThreadStateException" will be thrown
Method 2: implement Runnable interface
1) Defines the implementation class of the Runnable interface
2) Reproduce the run method of the interface
3) Create subclass objects
4) Pass a subclass object into the constructor of the Thread class
5) Start the Thread by calling the start method through the Thread, and call the run method in the Runnable implementation class
package com.example.www.d4; /** * @ClassName ThreadTest1 * @Description The second way to create multithreading is to implement the Runnable interface * 1.Create a class that implements the Runnable interface * 2.The implementation class implements the abstract method in Runnable: run() * 3.Create an object that implements the class * 4.Pass this object as a parameter to the constructor of the Thread class to create an object of the Thread class * 5.Call start() to start the current thread, and call run() of the current thread * @Author Jack * @Date 2021/11/22 7:27 * @Version 1.0 */ //1. Create an implementation class class MyThread3 implements Runnable{ //2. Implement the abstract method in Runnable @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+":"+i); } } } public class ThreadTest1 { public static void main(String[] args) { //3. Create an object that implements the class MyThread3 t3 = new MyThread3(); //4. Pass this object as a parameter to the construction method of Thread Thread t = new Thread(t3); //5. start the Thread through the object of Thread class, call the run -- > of the current Thread, and call the target of Runnable type t.start(); } }
4. Connection and difference between inheritance and Realization
public class Thread extends Object implements Runnable
difference
Inherit Thread: Thread code is stored in the run method of Thread subclass.
Implementation of Runnable: the thread code has the run method of the implementation class of the interface.
Benefits of implementation
The limitation of single inheritance is avoided
Multiple threads can share the object of the same interface implementation class, which is very suitable for multiple same threads to process the same resource.
5. Related methods of thread class
void start(): starts the thread and executes the run() method of the object
run(): the operation performed by the thread when it is scheduled
String getName(): returns the name of the thread
void setName(String name): sets the thread name
static Thread currentThread(): returns the current Thread. this is in the Thread subclass, which is usually used for the main Thread and Runnable implementation class
static void yield(): thread yield
Pause the thread currently executing and give the execution opportunity to the thread with the same or higher priority
If there are no threads with the same priority in the queue, this method is ignored
**join() 😗* When the join () method of other threads is invoked in a program execution stream, the calling thread will be blocked until the join thread added by the join () method is executed.
static void sleep(long millis): (specified time: ms)
Make the current active thread give up control over the CPU within the specified time period, so that other threads have the opportunity to be executed, and re queue when the time comes.
Throw InterruptedException exception
stop(): force the end of the thread lifetime. It is not recommended
boolean isAlive(): returns boolean to judge whether the thread is still alive
Java scheduling method
Threads with the same priority form a first in first out queue (first in first out service) and use the time slice strategy
For high priority, the preemptive strategy of priority scheduling is used
Priority level of the thread
​ MAX_ PRIORITY: 10
​ MIN_ PRIORITY: 1
​ NORM_ PRIORITY: 5
Methods involved
getPriority(): returns the thread priority value
setPriority(int newPriority): change the priority of the thread
explain
When a thread is created, it inherits the priority of the parent thread
Low priority only has a low probability of obtaining scheduling, and is not necessarily called after high priority threads
package com.example.www.d4; /** * @ClassName ThreadMethodTest * @Description Thread Common methods of * 1.start(): Start the current thread and call run() of the current thread * 2.run(): You usually need to override this method in the Thread class to write the operation to be performed by the Thread creation * 3.currentThread: Static method that returns the thread of the current code * 4.getName()Gets the name of the current thread * 5.setName Sets the name of the current thread * 6.yield(): Release current cpu execution rights * 7.join(): Call thread b join in thread a. At this point, thread a enters a blocking state until thread b completes, and thread a ends blocking state. * 8.stop()Obsolete. When this method is executed, the current thread is forced to end * 9.sleep(long milltime):Let the current thread sleep for the specified millitime milliseconds. Within the specified time, the thread is in a blocked state * 10.isAlive()Determine whether the thread is alive * <p> * <p> * thread priority * 1. * MAX_PRIORITY 10 * MIN_PRIORITY 1 * NORM_PRIORITRY 5 * 2.How to get and set the priority of the current thread * getPriority():Gets the priority of the thread * setPriority():Set thread priority * @Author Jack * @Date 2021/11/21 22:14 * @Version 1.0 */ public class ThreadMethodTest { public static void main(String[] args) { MyThread2 t1 = new MyThread2(); t1.setName("Thread 1"); //Set the priority of threads t1.setPriority(Thread.MAX_PRIORITY); t1.start(); Thread.currentThread().setName("Main thread"); Thread.currentThread().setPriority(Thread.MIN_PRIORITY); for (int i = 1; i < 100; i++) { System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i); // if (i % 20 ==0){ // try { // t1.join(); // } catch (InterruptedException e) { // e.printStackTrace(); // } // } } System.out.println(t1.isAlive()); } } class MyThread2 extends Thread { @Override public void run() { for (int i = 0; i < 100; i++) { if (i % 2 == 0) { // try { // sleep(20); // } catch (InterruptedException e) { // e.printStackTrace(); // } System.out.println(Thread.currentThread().getName() + ":" + getPriority() + ":" + i); } // if (i == 20) { // yield();// Release the execution rights of the current cpu //Thread 1:80 //Main thread: 75 //... when thread 1 releases the execution right of the current cpu, other threads will rob // } } } }
6. Classification of threads
Threads in Java are divided into two categories: one is daemon thread and the other is user thread.
They are the same in almost every way, and the only difference is to judge when the JVM leaves.
Daemon threads are used to serve user threads. By calling thread.setDaemon(true) before the start() method, a user thread can be turned into a daemon thread.
Java garbage collection is a typical daemon thread.
If there are daemon threads in the JVM, the current JVM will exit.
Image understanding: the rabbit dies and the dog cooks, and the birds hide
When the birds are gone, the bow will be hidden; After the rabbits were killed, the hounds were useless and cooked.
7. Thread life cycle
NEW
Runnable
Blocked
Waiting
Timed_waiting
Terminated
To implement multithreading, you must create a new Thread object in the main Thread. The Java language uses the objects of Thread class and its subclasses to represent threads. In a complete life cycle, it usually experiences the following five states:
New: when the object of a Thread class or its subclass is declared and created, the new Thread object is in the new state
state
Ready: after the thread in the new state is started (), it will enter the thread queue and wait for the CPU time slice. At this time, it has been started
The conditions for operation are met, but the CPU resources are not allocated
Run: when the ready thread is scheduled and obtains CPU resources, it enters the running state, and the run() method defines the line
Operation and function of the process
Blocking: in a special case, when the input / output operation is suspended or executed artificially, the CPU is released and temporarily suspended
Stop your own execution and enter the blocking state
Dead: the thread has completed all its work, or the thread is forcibly suspended in advance or terminated due to an exception
3, Thread synchronization
When multiple threads operate and share data together, the operation will be incomplete and the data will be destroyed
When multiple threads operate to share data, one thread only executes part of the statements, and the other thread also participates. Can cause errors in shared data
The code is as follows:
package com.example.www.d4; /** * @ClassName WindowTest * @Description Selling tickets * Example: create three windows to sell tickets, and the total number of tickets is 100 * There is now a thread security issue * @Author Jack * @Date 2021/11/21 23:33 * @Version 1.0 */ public class WindowTest { public static void main(String[] args) { Window w1 = new Window(); Window w2 = new Window(); Window w3 = new Window(); w1.setName("Window one"); w2.setName("Window II"); w3.setName("Window three"); w1.start(); w2.start(); w3.start(); } } class Window extends Thread { private static int ticket = 100; // private static Object obj =new Object(); @Override public void run() { while (true) { // synchronized (Window.class){ if (ticket > 0) { try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + ":Ticket number" + ticket); ticket--; }else { break; } // } } } } The output result is: ... ... Window three:Ticket No. 13 Window II:Ticket No. 13 Window one:Ticket No. 13 Window one:Ticket No. 10 Window three:Ticket No. 10 Window II:Ticket No. 8 Window three:Ticket No. 7 Window one:Ticket No. 6 Window II:Ticket No. 5 Window three:Ticket No. 4 Window II:Ticket No. 4 Window one:Ticket No. 4 Window three:Ticket number 1 Window II:Selling tickets, ticket number 0 Window one:Ticket number-1
resolvent:
When a thread operates on shared data, it cannot continue until it has finished operating on other threads
1. Usage of synchronized
Java provides a professional solution to this problem: synchronization mechanism
Understanding synchronization and asynchrony
Synchronous and asynchronous focus on message communication mechanisms
Synchronization is to call something. The caller has to wait for the return result of the call before continuing to execute later. Asynchrony and synchronization, the caller will not wait for the result, but after the call is issued, the caller can continue to perform subsequent operations. Which call will be processed first?
Synchronous and asynchronous, for example, five guests come to a restaurant. Synchronous means that the first one to order dishes and order a fish. OK, the chef goes to catch and kill fish. After half an hour, the fish is ready for the first guest and the next guest. Come one by one in this order
Similarly, asynchrony means to come to the first guest, order something, order fish, give it a brand and let him wait. The next guest then orders, and after ordering, let the cook do it. Whichever dish is good first comes out first,
The advantages of synchronization are: synchronization is carried out one by one in order, which will not be disordered, and the following code will not be executed before the above code is executed. The disadvantages are: the parsing speed is not as fast as asynchronous;
The advantages of asynchrony are: asynchrony is to take a task and directly give it to the background. It has always been like this before taking the next task. Who reads it first and executes it first. Disadvantages: there is no order. Who reads it first and executes it first will appear that the above code has already come out before the following code comes out, and an error will be reported;
1. Synchronization code block:
synchronized (object){
//Code to be synchronized;
2.synchronized can also be placed in the method declaration, indicating that the whole method is a synchronous method.
For example:
public synchronized void show (String name){
}
The implementation is as follows
package com.example.www.d4; /** * @ClassName WindowTest * @Description Selling tickets * Example: create three windows to sell tickets, and the total number of tickets is 100 * There is now a thread security issue * @Author Jack * @Date 2021/11/21 23:33 * @Version 1.0 */ public class WindowTest { public static void main(String[] args) { Window w1 = new Window(); Window w2 = new Window(); Window w3 = new Window(); w1.setName("Window one"); w2.setName("Window II"); w3.setName("Window three"); w1.start(); w2.start(); w3.start(); } } class Window extends Thread { private static int ticket = 100; // private static Object obj =new Object(); @Override public void run() { while (true) { synchronized (Window.class){ if (ticket > 0) { try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + ":Ticket number" + ticket); ticket--; }else { break; } } } } } The output results are as follows: ......... ......... Window three:Selling tickets, ticket number 20 Window three:Ticket No. 19 Window II:Ticket No. 18 Window II:Ticket No. 17 Window three:Ticket No. 16 Window three:Ticket No. 15 Window three:Ticket No. 14 Window three:Ticket No. 13 Window three:Ticket No. 12 Window three:Ticket No. 11 Window three:Ticket No. 10 Window three:Ticket No. 9 Window one:Ticket No. 8 Window three:Ticket No. 7 Window three:Ticket No. 6 Window three:Ticket No. 5 Window three:Ticket No. 4 Window three:Ticket No. 3 Window II:Ticket No. 2 Window three:Ticket number 1
2. Lock in synchronization mechanism
In Thinking in Java, it is said that for concurrent work, you need some way to prevent two tasks from accessing the same resources (in fact, shared resource competition) . the way to prevent this conflict is to lock a resource when it is used by a task. The first task accessing a resource must lock the resource so that other tasks cannot access it before it is unlocked. When it is unlocked, another task can lock and use it.
What is a synchronized lock?
Any object can be used as a synchronous lock. All objects automatically contain a single lock (monitor).
Lock of synchronous method: static method (class name). class), non static method (this)
Synchronous code block: you can specify it yourself, and it is often specified as this or class name
be careful
It is very important to ensure that multiple threads using the same resource share a lock, otherwise the security of shared resources cannot be guaranteed
All static methods in a thread class share the same lock (class name. class), all non static methods share the same lock (this), and synchronize code blocks (be careful when specifying)
Scope of synchronization
1. How to find the problem, that is, whether there is thread safety in the code? (very important)
(1) Identify which code is multithreaded
(2) Specify whether multiple threads share data
(3) Specify whether there are multiple statements operating on shared data in multithreaded running code
2. How to solve it?
(very important)
For statements with data shared by multiple operations, only one thread can complete the execution. During the execution, other threads cannot participate in the execution.
That is, all these statements that operate on shared data should be placed in the synchronization range
3. Remember
The scope is too small: not all code with security problems is locked
Too wide range: it does not play the function of multithreading.
Operation of releasing lock
The execution of the synchronization method and synchronization code block of the current thread ends.
The current thread encountered break and return in the synchronization code block and synchronization method, and terminated the code block
The method continues.
The current thread has an unhandled Error or Exception in the synchronization code block and synchronization method. Please lead
Cause abnormal end.
The current thread executes the wait() method of the thread object in the synchronization code block and synchronization method
The process pauses and releases the lock. (the wait method will be mentioned later)
Operation that does not release the lock
When a thread executes a synchronization code block or synchronization method, the program calls Thread. sleep() and Thread.yield() methods to suspend the execution of the current thread
When a thread executes a synchronization code block, other threads call the thread's suspend() method to suspend the thread, and the thread will not release the lock (synchronization monitor).
Try to avoid using suspend() and resume() to control threads
Thread deadlock
Different threads occupy the synchronization resources needed by the other party and do not give up. They are waiting for the other party to give up the synchronization resources they need, forming a thread deadlock
After a deadlock occurs, there will be no exception or prompt, but all threads are blocked and cannot continue
as follows
package com.caq.www; import static java.lang.Thread.sleep; /** * @ClassName ThreadTest * @Description Demonstrate thread deadlock * 1.Understanding of Deadlock: * Different threads occupy the synchronization resources required by each other and do not give up, * They are waiting for the other party to give up the public resources they need, which forms a thread deadlock * 2.explain: * 1)After a deadlock occurs, there will be no exception or prompt, but all threads are blocked and cannot continue * 2)When we use synchronization, we should avoid deadlock * @Author Jack * @Date 2021/11/23 11:13 * @Version 1.0 */ public class ThreadTest { public static void main(String[] args) { StringBuffer s1 = new StringBuffer(); StringBuffer s2 = new StringBuffer(); //Start a Thread by inheriting the Thread class through the anonymous inner class new Thread(new Runnable() { @Override public void run() { synchronized(s1){ s1.append("a"); s2.append("1"); //The thread holds the s1 lock and waits for the s2 lock try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (s2){ s1.append("b"); s2.append("2"); System.out.println(s1); System.out.println(s2); } } } }).start(); //Start a new thread by implementing the Runnable interface new Thread(new Runnable() { @Override public void run() { synchronized(s2){ s1.append("c"); s2.append("3"); //The thread holds the s2 lock and waits for the s1 lock try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (s1){ s1.append("d"); s2.append("4"); System.out.println(s1); System.out.println(s2); } } } }).start(); } }
resolvent
Special algorithms and principles
Minimize the definition of synchronization resources
Try to avoid nested synchronization
3. Lock
Starting from JDK 5.0, Java provides a more powerful thread synchronization mechanism. First, synchronization is achieved by explicitly defining the synchronization Lock object. The synchronization Lock uses the Lock object as the synchronization object.
The java.util.concurrent.locks.Lock interface is a tool that controls multiple threads to access shared resources. Locks provide exclusive access to shared resources. Only one thread can Lock the Lock object at a time. Threads should obtain the Lock object before accessing shared resources.
ReentrantLock class implements Lock. It has the same concurrency and memory semantics as synchronized. ReentrantLock is commonly used in thread safety control, which can explicitly add and release locks.
Improved example
package com.caq.www; import java.util.concurrent.locks.ReentrantLock; /** * @ClassName LockTest * @Description Three ways to solve thread safety problems: Lock lock -- new in JDK5.0 * * 1.Interview question: similarities and differences between synchronized and Lock * Same: both can solve thread safety problems * Difference: the synchronized mechanism automatically releases the synchronization monitor after executing the corresponding synchronization code * lock You need to manually start synchronization (lock ()), and you also need to manually execute (unlock ()) to end synchronization * * * 2.Interview question: how to create multithreading? * 1.Override the run method by inheriting the Thread class. Generate the object of the subclass and call the start method * 2.By implementing the Runnable interface and passing the implementation class as a parameter to the constructor of the Thread class, create a Thread object and call start() to start the Thread * * 3.Interview question: how to solve thread safety problems? How many ways? * 1.Synchronize code blocks and methods through synchronized {synchronization method} * 2.By means of Lock lock, manually open the synchronization Lock to synchronize threads, and manually release the synchronization Lock to end * * @Author Jack * @Date 2021/11/23 15:57 * @Version 1.0 */ class Window implements Runnable{ private int ticket = 100; //Instantiate ReentrantLock private ReentrantLock lock = new ReentrantLock(true);//If it is true, it is fair first in first out, and the default is false preemption @Override public void run() { while (true){ try { //2. Call the lock method lock lock.lock(); if (ticket > 0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":Ticket No.:"+ticket); ticket--; }else { break; } }finally { //3. Call unlocking method lock.unlock(); } } } } public class LockTest { public static void main(String[] args) { Window w = new Window(); Thread t1 = new Thread(w); Thread t2 = new Thread(w); Thread t3 = new Thread(w); t1.setName("Window one"); t2.setName("Window II"); t3.setName("Window three"); t1.start(); t2.start(); t3.start(); } }
Note: if there is an exception in the synchronization code, write unlock() to the finally statement block
synchronized vs Lock
- Lock is an explicit lock (manually open and close the lock, don't forget to close the lock), and synchronized is an implicit lock, which is automatically released out of the scope
- Lock only has code block lock, and synchronized has code block lock and method lock
- Using Lock lock, the JVM will spend less time scheduling threads and perform better. And it has better extensibility (providing more subclasses)
- Priority:
Lock - > synchronization code block (it has entered the method body and allocated corresponding resources) - > synchronization method (outside the method body)
4, Thread communication
It can be understood as alternation
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 ntifyll() 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 queued for resources and ends waiting
These three methods can only be used in the synchronized method or synchronized code block, otherwise java.langlegalmonitorstateexception will be reported.
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.
example
package com.caq.java2; /** * @ClassName CommunicatrionTEst * @Description Examples of thread communication; Use two threads to print 1-100. Thread 1, thread 2, alternate printing * * 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 wait thread will wake up. If multiple threads are limited by wait, the thread with high priority will be released * nitifyAll(): Once this method is executed, all wait threads will wake up * * explain: * 1.wait, notify(),nitifyAll()The three methods must be used in synchronous code blocks or synchronous methods * 2.wait, notify(),nitifyAll()The three method callers must be synchronization monitors in synchronization blocks or synchronization methods * 3.wait, notify(),nitifyAll()All three methods are methods in the java.lang.Object class * Otherwise, an IllegalMonitorStateException will occur * * Interview question: similarities and differences between sleep () and wait () methods * The same thing: once the method is executed, the thread will be blocked * Differences: 1) the positions of the two method declarations are inconsistent. One is Thread and the other is Object * 2)The call requirements are inconsistent. The sleep () method can be called in any need scenario, and the wait () must be used in the 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 Jack * @Date 2021/11/23 22:52 * @Version 1.0 */ class Number implements Runnable{ private int number = 1; @Override public void run() { while (true){ synchronized (this) { notify();//When the thread 1 wait, release the lock. Thread 2 comes in and calls notify to wake up thread 1 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 //Entering the wait state will release the lock 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(); } }
Producer / consumer issues
package com.caq.java2; /** * @ClassName ProductTest * @Description 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 (e.g. 20) at a time. If the producer tries to produce more products, the clerk will * The manufacturer will be asked to stop. If there is a space in the store for products, the manufacturer will be notified to continue production: if there is no product in the store * The clerk will tell the consumer to wait a minute and inform the consumer to take the product if there is a product in the store. * <p> * 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 security problem? Synchronization mechanism, there are three methods * 4.Is thread communication involved? yes * @Author Jack * @Date 2021/11/23 23:21 * @Version 1.0 */ 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 { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } //wait for } } //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 { sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } clerk.produceProduct(); } } } class Consumer extends Thread { private Clerk clerk; public Consumer(Clerk clerk) { this.clerk = clerk; } @Override public void run() { while (true) { try { 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); Consumer c1 = new Consumer(clerk); Consumer c2 = new Consumer(clerk); p1.setName("producer"); p1.start(); c1.setName("Consumer 1"); c2.setName("Consumer 2"); c1.start(); c2.start(); } }
5, JDK5.0 new thread creation method
1. Implement Callable interface
Callable is more powerful than Runnable
Compared with the run() method, you can have a return value
Method can throw an exception
Return values that support generics
You need to use the Future Task class, for example, to get the returned results
Future interface
You can cancel the execution results of specific Runnable and Callable tasks, query whether they are completed, obtain results, etc.
FutrueTask is the only implementation class of Futrue interface
FutureTask also implements Runnable and Future interfaces. It can be executed by the thread as Runnable or get the return value of Callable as Future
Examples are as follows
package com.caq.java2; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * @ClassName ThreadNew * @Description The third way to create a thread * Implement Callable interface -- jdk5.0 * * How to understand that the way to implement the Callable interface to create multithreads is more powerful than the way to implement the Runnable interface to create multithreads? * 1.call()Can have return value * 2.call()Exceptions can be thrown and caught by external operations. Get exception information * 3.Callable It supports introspection * * * @Author Jack * @Date 2021/11/24 8:41 * @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 executed by this thread in call() @Override public Object call() throws Exception { int sum = 0; for (int i = 0; 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 the Callable interface implementation class as a parameter to the FutureTask constructor to create the FutureTask object 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 get () is the return value of call () overridden by the FutureTask constructor parameter Callable Object sum = futureTask.get(); System.out.println(sum); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
2. Use thread pool
background
Frequently create and destroy resources that are heavily used, such as threads in concurrency, which has a great impact on performance
thinking
Create multiple threads in advance, put them into the thread pool, obtain them directly when using them, and put them back into the pool after use. It can avoid frequent creation, destruction and reuse. Similar to public transport in life
advantage
Improved response time (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: when the thread has no task, how long will it last at most and then terminate
...
Thread pool related API
JDK 5.0 provides thread pool related APIs: executorservice and Executors
ExecutorService: the real thread pool interface. Common subclass ThreadPoolExecutor
void execute(Runnable command): executes a task / command without a return value. It is generally used to execute Runnable
Future submit(Callable task): execute a task with a return value, and generally execute a Callable task
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
example
package com.caq.java2; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; /** * @ClassName ThreadPool * @Description Four ways to create threads: * Use thread pool * Benefits: * 1.Improved response time (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:When a thread has no task, how long will it last at most and then terminate * * How many ways to create multithreading? * Four! * * @Author Jack * @Date 2021/11/24 9:13 * @Version 1.0 */ class NumberThread implements Runnable { @Override public void run() { for (int i = 0; i < 101; 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 < 101; i++) { if (i % 2 != 0) { System.out.println(Thread.currentThread().getName()+":"+i); } } } } public class ThreadPool { public static void main(String[] args) { //Executors.newFixedThreadPool(n); Create a reusable thread pool with a fixed number of threads //1. Provide a thread pool with a specified number of threads ExecutorService service = Executors.newFixedThreadPool(10); ThreadPoolExecutor service1 = (ThreadPoolExecutor) service; service1.setCorePoolSize(15); // service1.setKeepAliveTime(); //Set the properties of the thread pool System.out.println(service.getClass());//ThreadPoolExecutor /**The purpose of providing parameters is to tell the thread what to do NumberThread numberThread = new NumberThread(); service.execute(numberThread); Implementation of anonymous classes */ //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());//For Runnable service.execute(new NumberThread1()); // service.submit(Callable callable) is suitable for Callable //3. Close thread pool service.shutdown(); } }