1. Review
-
Interface
① Method (by jdk version)
② Multiple inheritance
③ Variable characteristics
④ One of the prerequisites of polymorphism
⑤ Factory design mode, at least know the simple factory
⑥ vs abstract class
-
abnormal
① Abnormal ancestor class: Throwable
② Classification of exceptions: compilation (inspected) + operation (non inspected)
③ error: I can't handle it
④ Common exceptions (at least 5): arithmetic, subscript out of bounds, null pointer, type conversion, input mismatch
⑤ Mechanism of catch to the caller
⑥ The difference between throw and throws
⑤ Custom exception
2. Thread
2.1 thread introduction [understand]
2.1.1 basic knowledge
- Program: static code collection
- Process: the program being executed, the unit in which the CPU allocates resources
- Thread: it is an execution path of a process and a subset of the process. Take Xunlei as an example. Using Xunlei can perform multiple download tasks. The advantage is to improve the execution efficiency of the program
2.1.2 understanding of single core CPU and multi-core CPU
- Single core CPU is actually a fake multithreading, because it can only execute one thread in a time unit. For example: Although there are multiple lanes, there is only one staff member in the toll station charging. Only after charging can it pass through, so the CPU is like a toll collector. If someone doesn't want to pay, the toll collector can "hang" him (hang him until he has figured it out and has the money ready). But because the CPU time unit is very short, I 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 Exe, in fact, there are at least three threads: main() main thread, gc() garbage collection thread and exception handling thread. Of course, if an exception occurs, it will affect the main thread.
2.1.3 concurrency and parallelism
For example, if a canteen has 8 windows and 8 people eat at different windows at the same time, it is called parallelism of 8
Concurrency: two or more events occur in the same time period. 8 windows, it takes 30s for each person to cook, then the concurrency is 16 within 1 minute
One CPU (using time slice) executes multiple tasks at the same time. For example: second kill, multiple people do the same thing.
Parallel: two or more events occur at the same time (at the same time). Multiple CPU s execute multiple tasks at the same time.
In a single core CPU, we feel that multiple tasks are executed at the same time. In fact, it is not. The CPU adopts the time-sharing polling mechanism, that is, its switching speed is fast, so we can't feel it.
In short: after a program runs, there is at least one process, and a process can contain multiple threads
2.1.4 when multithreading is required
- The program needs to perform two or more tasks at the same time.
- When the program needs to realize some tasks that need to wait, such as user input, file reading and writing operation, network operation, search, etc.
- When you need some programs running in the background.
2.1.5 significance, benefits and precautions of high concurrency programming
2.1.5.1 benefits of multithreading
Improve cpu utilization
Single thread:
5 seconds reading file A 2 seconds processing file A 5 seconds reading file B 2 seconds processing file B ----------------------- 14 seconds total
Multithreading
5 seconds reading file A 5 seconds reading file B + 2 seconds processing file A 2 seconds processing file B ----------------------- 12 seconds total
Generally speaking, when waiting for disk IO, network IO or user input, the CPU can process other tasks at the same time.
More efficient response
Multithreading technology makes the response speed of the program faster, because the user interface can always be active while doing other work, and will not cause the phenomenon of being unable to respond.
Fair use of CPU resources
For tasks that are not currently being processed, you can give processor time to other tasks; Tasks that take up a lot of processing time can also give processor time to other tasks regularly; Through the division of CPU time, the CPU time slice can be switched between multiple threads, so as to avoid threads that need to process for a long time monopolizing the CPU, resulting in other threads waiting for a long time.
2.1.5.2 cost of multithreading
More complex design
Reading of shared data, data security, interaction between threads, thread synchronization, etc;
Context switching
For thread switching, cpu needs to save local data, program pointer and other contents;
More resource consumption
Each thread needs memory to maintain its own local stack information, and the operating system also needs resources to manage and maintain threads;
2.2 method of creating thread [ high frequency interview ]
-
The first two are the most basic and must be able to
-
To start a thread, you need to call the start method instead of the run method [calling run is actually an ordinary method call]
-
Inheriting the Thread class is actually implementing the Runnable interface
public class Thread implements Runnable
-
The difference between inheriting Thread and implementing Runnable interface
① It can avoid the limitation of singleton inheritance in java
② Multiple threads can share the object of the same interface implementation class, which is very suitable for multiple threads to process the same resource.
③ Realize decoupling operation, code can be shared by multiple threads, and code and thread are independent [coupling and decoupling]
④ The Thread pool can only put threads that implement Runable or Callable classes, not directly into classes that inherit threads
-
The difference between Callable interface and runnable interface
① Common ground: threads can be implemented
② The call method of Callable has a return value, while the run method of Runnable has no return value
③ The call of Callable throws an exception, but the run does not throw an exception
④ Or to get the execution result, you need to use Callable, futureask get()
2.2.1 inherit Thread
Common construction methods:
- Thread(): create a new thread object
- Thread(String threadname): creates a thread and specifies 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
- Thread(FutureTask target): take FutureTask as the parameter. FutureTask is the packaging of Callable
- Write a class to inherit Thread
- Override run method
- Create a Thread subclass object, that is, create a Thread object.
- Call the thread object start method: start the thread and call the run method.
/** * Thread creation mode 1: * 1,Create: inherit Thread + override run * 2,Start: create subclass object + start * */ public class StartThread extends Thread{ /** * Thread entry point */ @Override public void run() { for(int i=0;i<20;i++) { System.out.println("While listening to the song"); } } public static void main(String[] args) { //Create subclass object StartThread st =new StartThread(); //start-up st.start(); //cpu calls are not guaranteed to run immediately //st.run(); // Ordinary method call for(int i=0;i<20;i++) { System.out.println("one side coding"); } } }
be careful:
- If you call the run() method manually, it's just an ordinary method without starting the multithreading mode.
- 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.
- To start multithreading, you must call the start method.
- A thread object can only call the start() method once to start. If it is called repeatedly, an exception IllegalThreadStateException will be thrown.
2.2.2 implementation of Runnable interface
Steps:
- Define subclasses and implement Runnable interface
- Override the run method in the Runnable interface in the subclass
- Create a Thread object through the Thread class parameter constructor
- Pass the subclass object of Runnable interface as the actual parameter to the constructor of Thread class
- Call the start method of Thread class: start the Thread and call the run method of Runnable subclass interface
public class TestMyTread2 { public static void main(String[] args) throws InterruptedException { //Create a thread object MyThread2 myThread = new MyThread2(); Thread thread = new Thread(myThread,"win1"); thread.start(); //Create a Runnable object using lambda Runnable r1 = () -> { for (int i = 0; i < 50; i++) { System.out.println(Thread.currentThread().getName()+":" + i); } }; //Start a thread using an anonymous object new Thread(r1,"win2").start(); for (int i = 0; i < 50; i++) { System.out.println(Thread.currentThread().getName()+":"+i); // Thread.sleep(100); } } } class MyThread2 implements Runnable { @Override public void run() { for (int i = 0; i < 50; i++) { System.out.println(Thread.currentThread().getName()+":" + i); } } }
/** * lambda deduction * @author azzhu */ public class LambdaTest04 { public static void main(String[] args) { new Thread(()->{ for(int i=0;i<100;i++) { System.out.println("While learning lambda"); } }) .start(); new Thread(()-> System.out.println("While learning to run")) .start(); } }
2.2.3 implementation of Callable interface - elevation
JDK5.0: add method 1, which is in the JUC package
-
Write a class to implement the Callable interface
-
Start thread
① Create a FutureTask object ft, new FutureTask(Callable object)
② Create a thread class to start the thread. new Thread(ft).start
Note: FutureTask
public class FutureTask<V> implements RunnableFuture<V> //============== public interface RunnableFuture<V> extends Runnable, Future<V>
③ When you need to get a value, get it
ft.get(); //The method has a return value
public class TestMyCallable { public static void main(String[] args) throws Exception { MyThread3 myThread3 = new MyThread3(); //Integer sum = myThread3.call(); //System.out.println(sum); FutureTask<Integer> futureTask = new FutureTask<>(myThread3); new Thread(futureTask).start(); //Start thread Integer result = futureTask.get(); System.out.println("====>" + result); } } class MyThread3 implements Callable<Integer> { @Override public Integer call() throws Exception { return 100; } }
2.2.4 practice
-
Create two sub threads, one of which outputs an even number between 1-100 and the other outputs an odd number between 1-100.
-
Use the above three methods to simulate the thunderbolt download task
Tools:
import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import org.apache.commons.io.FileUtils; /** * Download pictures */ public class WebDownloader { /** * download * @param url * @param name */ public void download(String url,String name) { try { FileUtils.copyURLToFile(new URL(url), new File(name)); } catch (MalformedURLException e) { e.printStackTrace(); System.out.println("illegal url"); } catch (IOException e) { e.printStackTrace(); System.out.println("Download failed"); } } }
- Inherit Thread
public class TDownloader extends Thread { private String url; //Remote path private String name; //Storage name public TDownloader(String url, String name) { this.url = url; this.name = name; } @Override public void run() { WebDownloader wd =new WebDownloader(); wd.download(url, name); System.out.println(name); } public static void main(String[] args) { TDownloader td1 =new TDownloader("http://upload.news.cecb2b.com/2014/0511/1399775432250.jpg","phone.jpg"); TDownloader td2 =new TDownloader("http://p1.pstatp.com/large/403c00037462ae2eee13","spl.jpg"); TDownloader td3 =new TDownloader("http://5b0988e595225.cdn.sohucs.com/images/20170830/d8b57e0dce0d4fa29bd5ef014be663d5.jpeg","success.jpg"); //Start three threads td1.start(); td2.start(); td3.start(); } }
- Implement Runnable
public class IDownloader implements Runnable{ private String url; //Remote path private String name; //Storage name public IDownloader(String url, String name) { this.url = url; this.name = name; } @Override public void run() { WebDownloader wd =new WebDownloader(); wd.download(url, name); System.out.println(name); } public static void main(String[] args) { IDownloader td1 =new IDownloader("http://upload.news.cecb2b.com/2014/0511/1399775432250.jpg","phone.jpg"); IDownloader td2 =new IDownloader("http://p1.pstatp.com/large/403c00037462ae2eee13","spl.jpg"); IDownloader td3 =new IDownloader("http://5b0988e595225.cdn.sohucs.com/images/20170830/d8b57e0dce0d4fa29bd5ef014be663d5.jpeg","success.jpg"); //Start three threads new Thread(td1).start(); new Thread(td2).start(); new Thread(td3).start(); } }
- Implement Callable
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * Understand three ways to create threads: * * @author azzhu * */ public class CDownloader implements Callable<Boolean>{ private String url; //Remote path private String name; //Storage name public CDownloader(String url, String name) { this.url = url; this.name = name; } @Override public Boolean call() throws Exception { WebDownloader wd =new WebDownloader(); wd.download(url, name); System.out.println(name); return true; } public static void main(String[] args) throws InterruptedException, ExecutionException { CDownloader cd1 =new CDownloader("http://upload.news.cecb2b.com/2014/0511/1399775432250.jpg","phone.jpg"); CDownloader cd2 =new CDownloader("http://p1.pstatp.com/large/403c00037462ae2eee13","spl.jpg"); CDownloader cd3 =new CDownloader("http://5b0988e595225.cdn.sohucs.com/images/20170830/d8b57e0dce0d4fa29bd5ef014be663d5.jpeg","success.jpg"); //Create execution service: thread pool ExecutorService ser=Executors.newFixedThreadPool(3); //Submit for execution: Future<Boolean> result1 =ser.submit(cd1) ; Future<Boolean> result2 =ser.submit(cd2) ; Future<Boolean> result3 =ser.submit(cd3) ; //Get results: boolean r1 =result1.get(); boolean r2 =result1.get(); boolean r3 =result1.get(); System.out.println(r3); //Shut down service: ser.shutdownNow(); } }
2.3 classification of threads
Threads fall into two categories:
- User thread: user thread
- Daemon thread: daemon thread. Die with the main thread
Daemon thread: supporting work, recovery and scheduling of memory resources, etc. finally, there is no guarantee of execution. [System.exit()]
Image understanding: the rabbit dies and the dog cooks, and all the birds hide
Setting a thread as a daemon thread: it needs to be set before the thread starts
Java garbage collection is a typical daemon thread.
myThread.setDaemon(true);
/** * Daemon thread: it serves user threads; The jvm stops without waiting for the daemon thread to finish executing * Default: the user thread jvm waits for the user thread to finish executing before stopping * @author azzhu * */ public class DaemonTest { public static void main(String[] args) { God god = new God(); You you = new You(); Thread t =new Thread(god); t.setDaemon(true);//Adjust user thread to daemon t.start(); new Thread(you).start(); } } class You implements Runnable{ @Override public void run() { for(int i=1;i<=365*100;i++) { System.out.println("happy life..."); } System.out.println("ooooo....."); } } class God implements Runnable{ @Override public void run() { for(;true;) { System.out.println("bless you..."); } } }
public class OnlyMain { public static void main(String[] args) { //Interface of virtual machine thread management ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); /* [6] Monitor Ctrl-Break [5] Attach Listener Be responsible for obtaining various information related to the running of the current main program [4] Signal Dispatcher Distribute threads that process signals to virtual machines [3] Finalizer The thread that calls the finalize method of the object [2] Reference Handler Clear referenced threads [1] main * */ ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false); for (ThreadInfo threadInfo : threadInfos) { System.out.println("["+threadInfo.getThreadId()+"]"+" "+threadInfo.getThreadName()); } } }
2.4 thread status / life cycle [high frequency interview]
public class Demo2 { public static Thread thread1; public static Demo2 obj; public static void main(String[] args) throws Exception { // The first state switch - New - > Run - > terminate System.out.println("#######First state switching - newly build -> function -> termination################################"); Thread thread1 = new Thread(new Runnable() { @Override public void run() { System.out.println("thread1 Current status:" + Thread.currentThread().getState().toString()); System.out.println("thread1 Yes"); } }); System.out.println("Not called start method, thread1 Current status:" + thread1.getState().toString()); thread1.start(); Thread.sleep(2000L); // Wait for thread1 execution to end, and then look at the status System.out.println("Wait two seconds and watch again thread1 Current status:" + thread1.getState().toString()); // thread1.start(); TODO: when calling after the thread terminates, an IllegalThreadStateException will be thrown System.out.println(); System.out.println("############Second: New -> function -> wait for -> function -> termination(sleep mode)###########################"); Thread thread2 = new Thread(new Runnable() { @Override public void run() { try {// Move thread 2 to the waiting state and wake up automatically after 1500 Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("thread2 Current status:" + Thread.currentThread().getState().toString()); System.out.println("thread2 Yes"); } }); System.out.println("Not called start method, thread2 Current status:" + thread2.getState().toString()); thread2.start(); System.out.println("call start method, thread2 Current status:" + thread2.getState().toString()); Thread.sleep(200L); // The main thread waits 200 milliseconds to see the status System.out.println("Wait for 200 milliseconds and watch again thread2 Current status:" + thread2.getState().toString()); Thread.sleep(3000L); // The main thread waits another 3 seconds to finish thread2 execution, and then looks at the status System.out.println("Wait 3 seconds and watch again thread2 Current status:" + thread2.getState().toString()); System.out.println(); System.out.println("############Third: New -> function -> block -> function -> termination###########################"); Thread thread3 = new Thread(new Runnable() { @Override public void run() { synchronized (Demo2.class) { System.out.println("thread3 Current status:" + Thread.currentThread().getState().toString()); System.out.println("thread3 Yes"); } } }); synchronized (Demo2.class) { System.out.println("Not called start method, thread3 Current status:" + thread3.getState().toString()); thread3.start(); System.out.println("call start method, thread3 Current status:" + thread3.getState().toString()); Thread.sleep(200L); // The main thread waits 200 milliseconds to see the status System.out.println("Wait for 200 milliseconds and watch again thread3 Current status:" + thread3.getState().toString()); } Thread.sleep(3000L); // The main thread waits another 3 seconds to finish thread3 execution, and then looks at the status System.out.println("Wait 3 seconds for thread3 Grab the lock and look again thread3 Current status:" + thread2.getState().toString()); } }
2.5 thread synchronization / safety [high frequency interview]
2.5.1 problem elicitation
Simulate the ticket selling program of the railway station and open three windows to sell tickets.
class Ticket implements Runnable { private int tick = 100; public void run() { while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if (tick > 0) { System.out.println(Thread.currentThread().getName() + "Tickets sold, tick The number is:" +tick--); } else break; } } }
class TicketDemo { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); t1.setName("t1 window"); t2.setName("t2 window"); t3.setName("t3 window"); t1.start(); t2.start(); t3.start(); } }
-
There is a security problem with multithreading
-
Cause of the problem
When multiple statements are operating on the same thread to share data, one thread only executes part of multiple statements, and another thread participates in the execution. The error that caused the shared data. If the data is owned by each thread independently, there will be no thread safety problem.
-
Solution: use lock mechanism
For statements that share data with multiple operations, only one thread can be executed. During the execution process, other threads cannot participate in the execution, that is, synchronization mechanism and lock.
synchronized: lock method or code block
Lock interface: manually lock and unlock ReentrantLock class
2.5.2 synchronization method
The granularity [coarse granularity] is relatively large. Lock up the whole method
private synchronized void sellTicket() { if(i > 0) { try { System.out.println(Thread.currentThread().getName() +"Sold section:"+(50-i+1)+",There are three left:"+(--i)); Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }
2.5.3 synchronization code block
In addition to the code blocks that may be thread safe, lock them with a lock and synchronize them (this gets any other object), so as to ensure that they are a lock object lock
synchronized (Ticket.class) {} class lock
https://segmentfault.com/a/1190000017766364 Various locks in concurrency
synchronized (this) { if(i > 0) { try { System.out.println(Thread.currentThread().getName() +"Sold section:"+(50-i+1)+",Remaining:"+(--i)); Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }
2.5.4 Lock lock
- Starting from JDK 5.0, Java has provided a more powerful thread synchronization mechanism -- synchronization is achieved by explicitly defining synchronization Lock objects. Synchronous locks use Lock objects as.
- 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.
//Manual locking + unlocking try { lock.lock(); if(i > 0) { System.out.println(Thread.currentThread().getName() +"Sold section:"+(50-i+1)+",There are three left:"+(--i)); Thread.sleep(10); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); }
2.5.5 thread safe alternatives to ArrayList
ArrayList thread unsafe:
public class UnsafeTest03 { public static void main(String[] args) throws InterruptedException { List<String> list = new ArrayList<String>(); for(int i=0;i<10000;i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }) .start(); } System.out.println(list.size()); } }
Locking:
public class SynBlockTest02 { public static void main(String[] args) throws InterruptedException { List<String> list = new ArrayList<String>(); for(int i=0;i<10000;i++) { new Thread(()->{ //Synchronization block synchronized(list) { list.add(Thread.currentThread().getName()); } }) .start(); } Thread.sleep(10000); System.out.println(list.size()); } }
CopyOnWriteArrayList
Taking the source code of the add method as an example, we find that the lock lock [display lock] is added to all operations related to writing [add and delete]:
public boolean add(E e) { final ReentrantLock lock = this.lock; //Lock lock lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } }
public class SynContainer { public static void main(String[] args) throws InterruptedException { CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>(); for(int i=0;i<10000;i++) { new Thread(()->{ list.add(Thread.currentThread().getName()); }) .start(); } Thread.sleep(10000); System.out.println(list.size()); } }
Can you explain the principle of CopyOnWriteArrayList?
reference: https://zhuanlan.zhihu.com/p/84485589
2.5.6 lazy style of singleton design mode (thread safety)
class Singleton { //Without volatile, other threads may access an object that is not initialized private static volatile Singleton instance; private Singleton() { } public static Singleton getInstance() { //Detect again to avoid unnecessary synchronization. Existing objects if (instance == null) { synchronized (Singleton.class) { if (instance == null) { //1. Open up space / / 2. Initialize object information / / 3. Return the address of the object to the reference instance = new Singleton(); } } } return instance; } } public class SingletonTest { public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); System.out.println(s1 == s2); } }
2.5.7 thread deadlock
- 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
- resolvent
- Special algorithms and principles
- Minimize the definition of synchronization resources
- Try to avoid nested synchronization
class A { public synchronized void foo(B b) { System.out.println("Current thread name: " + Thread.currentThread().getName() + " Entered A Instance foo method"); // ① try { Thread.sleep(200); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println("Current thread name: " + Thread.currentThread().getName() + " Attempt to call B Instance last method"); // ③ b.last(); } public synchronized void last() { System.out.println("Entered A Class last Method internal"); } } class B { public synchronized void bar(A a) { System.out.println("Current thread name: " + Thread.currentThread().getName() + " Entered B Instance bar method"); // ② try { Thread.sleep(200); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println("Current thread name: " + Thread.currentThread().getName() + " Attempt to call A Instance last method"); // ④ a.last(); } public synchronized void last() { System.out.println("Entered B Class last Method internal"); } } public class DeadLock implements Runnable { A a = new A(); B b = new B(); public void init() { Thread.currentThread().setName("Main thread"); // Call foo method of a object a.foo(b); System.out.println("After entering the main thread"); } public void run() { Thread.currentThread().setName("Secondary thread"); // Call the bar method of the b object b.bar(a); System.out.println("After entering the secondary thread"); } public static void main(String[] args) { DeadLock dl = new DeadLock(); new Thread(dl).start(); dl.init(); } }
C:\Users\Administrator>jps 13872 KotlinCompileDaemon 724 12008 RemoteMavenServer 14104 DeadLock 13692 Jps 7852 NailgunRunner C:\Users\Administrator>jstack -l 14104 2020-06-14 22:29:38 Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode): "Secondary thread" #12 prio=5 os_prio=0 tid=0x000000002847a800 nid=0x32a0 waiting for monitor entry [0x00000000291cf000] java.lang.Thread.State: BLOCKED (on object monitor) at cn.azzhu.A.last(DeadLock.java:18) - waiting to lock <0x000000071628e238> (a cn.azzhu.A) at cn.azzhu.B.bar(DeadLock.java:33) - locked <0x00000007162905e8> (a cn.azzhu.B) at cn.azzhu.DeadLock.run(DeadLock.java:55) at java.lang.Thread.run(Thread.java:748) "Service Thread" #11 daemon prio=9 os_prio=0 tid=0x00000000283b6800 nid=0xdb8 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C1 CompilerThread3" #10 daemon prio=9 os_prio=2 tid=0x000000002830a000 nid=0x3a54 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x00000000282dd800 nid=0x36b4 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x00000000281ef000 nid=0x24d8 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x00000000281ee800 nid=0x36b0 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x00000000282ab800 nid=0x2264 runnable [0x0000000028ace000] java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:171) at java.net.SocketInputStream.read(SocketInputStream.java:141) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) - locked <0x00000007164e3660> (a java.io.InputStreamReader) at java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.BufferedReader.fill(BufferedReader.java:161) at java.io.BufferedReader.readLine(BufferedReader.java:324) - locked <0x00000007164e3660> (a java.io.InputStreamReader) at java.io.BufferedReader.readLine(BufferedReader.java:389) at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64) "Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000027b65800 nid=0x1b58 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000000027b0c000 nid=0x231c runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000002c9d800 nid=0x1740 in Object.wait() [0x0000000027fcf000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x0000000715f88ec8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143) - locked <0x0000000715f88ec8> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209) "Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000002c9c000 nid=0xb34 in Object.wait() [0x0000000027acf000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x0000000715f86b68> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:502) at java.lang.ref.Reference.tryHandlePending(Reference.java:191) - locked <0x0000000715f86b68> (a java.lang.ref.Reference$Lock) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153) "Main thread" #1 prio=5 os_prio=0 tid=0x000000000243c800 nid=0x1184 waiting for monitor entry [0x00000000029ef000] java.lang.Thread.State: BLOCKED (on object monitor) at cn.azzhu.B.last(DeadLock.java:37) - waiting to lock <0x00000007162905e8> (a cn.azzhu.B) at cn.azzhu.A.foo(DeadLock.java:14) - locked <0x000000071628e238> (a cn.azzhu.A) at cn.azzhu.DeadLock.init(DeadLock.java:48) at cn.azzhu.DeadLock.main(DeadLock.java:62) "VM Thread" os_prio=2 tid=0x0000000025c0a000 nid=0x2f9c runnable "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002bbb800 nid=0x38c4 runnable "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002bbd000 nid=0x3b1c runnable "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000002bbe800 nid=0x3960 runnable "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000000002bc1000 nid=0x38ec runnable "GC task thread#4 (ParallelGC)" os_prio=0 tid=0x0000000002bc3000 nid=0x3a00 runnable "GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000002bc4800 nid=0x3860 runnable "GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000002bc7800 nid=0x2d58 runnable "GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000002bc8800 nid=0x3614 runnable "VM Periodic Task Thread" os_prio=2 tid=0x000000002830c800 nid=0x17c4 waiting on condition JNI global references: 33 Found one Java-level deadlock: ============================= "Secondary thread": waiting to lock monitor 0x0000000025c13588 (object 0x000000071628e238, a cn.azzhu.A), which is held by "Main thread" "thread??": waiting to lock monitor 0x0000000025c12038 (object 0x00000007162905e8, a cn.azzhu.B), which is held by "Secondary thread" Java stack information for the threads listed above: =================================================== "Secondary thread": at cn.azzhu.A.last(DeadLock.java:18) - waiting to lock <0x000000071628e238> (a cn.azzhu.A) at cn.azzhu.B.bar(DeadLock.java:33) - locked <0x00000007162905e8> (a cn.azzhu.B) at cn.azzhu.DeadLock.run(DeadLock.java:55) at java.lang.Thread.run(Thread.java:748) "thread???": at cn.azzhu.B.last(DeadLock.java:37) - waiting to lock <0x00000007162905e8> (a cn.azzhu.B) at cn.azzhu.A.foo(DeadLock.java:14) - locked <0x000000071628e238> (a cn.azzhu.A) at cn.azzhu.DeadLock.init(DeadLock.java:48) at cn.azzhu.DeadLock.main(DeadLock.java:62) Found 1 deadlock. //Indicates that a deadlock was found
/** * Deadlock: too many synchronizations may cause mutual non release of resources * Thus, they wait for each other, which usually occurs when they hold locks of multiple objects in synchronization * * Avoid: do not hold locks on multiple objects at the same time in the same code block * * @author azzhu * */ public class DeadLock { public static void main(String[] args) { Markup g1 = new Markup(1,"Cecilia Cheung"); Markup g2 = new Markup(0,"Faye Wong"); g1.start(); g2.start(); } } //Lipstick class Lipstick{ } //mirror class Mirror{ } //Make up class Markup extends Thread{ static Lipstick lipstick = new Lipstick(); static Mirror mirror = new Mirror(); //choice int choice; //name String girl; public Markup(int choice,String girl) { this.choice = choice; this.girl = girl; } @Override public void run() { //Make up markup(); } //Holding each other's object lock -- > may cause deadlock private void markup() { if(choice==0) { synchronized(lipstick) { //Get lipstick lock System.out.println(this.girl+"rouge sb.'s lips"); //I want to have the lock of the mirror in one second try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } /* synchronized(mirror) { System.out.println(this.girl+"Look in the mirror "); }*/ } synchronized(mirror) { System.out.println(this.girl+"Look in the mirror"); } }else { synchronized(mirror) { //Get the lock of the mirror System.out.println(this.girl+"Look in the mirror"); //Want to have a lipstick lock in 2 seconds try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } /* synchronized(lipstick) { System.out.println(this.girl+"Apply lipstick ""); } */ } synchronized(lipstick) { System.out.println(this.girl+"rouge sb.'s lips"); } } } }
2.5.8 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 scalability (providing more subclasses)
The synchronized code is concise, and the performance has a great hint compared with the beginning
Lock: obtaining the lock can be interrupted. Obtain the lock after timeout and try to obtain the lock; Read and write more and use less read and write lock
Unless there are requirements in 3 above, try to use synchronized
Priority order: Lock → sync code block (has entered the method body and allocated corresponding resources) → sync method
(outside the method body)
2.5.9 ConcurrentHashMap
slightly
2.5.10 thread safety Case Supplement
-
Happy train ticket
public class Happy12306 { public static void main(String[] args) { Web12306 c = new Web12306(4,"happy sxt"); new Passenger(c,"fairly tall",2).start(); new Passenger(c,"Lao Pei",1).start(); } } //customer class Passenger extends Thread{ int seats; public Passenger(Runnable target,String name,int seats) { super(target,name); this.seats = seats; } } //Train ticket network class Web12306 implements Runnable{ int available; //Available locations String name; //name public Web12306(int available, String name) { this.available = available; this.name = name; } public void run() { Passenger p = (Passenger)Thread.currentThread(); boolean flag = this.bookTickets(p.seats); if(flag) { System.out.println("Ticket issued successfully"+Thread.currentThread().getName()+"-<Location is:"+p.seats); }else { System.out.println("Ticket issuing failed"+Thread.currentThread().getName()+"-<Insufficient position"); } } //Ticket purchase public synchronized boolean bookTickets(int seats) { System.out.println("Available locations are:"+available); if(seats>available) { return false; } available -=seats; return true; } }
-
Happy cinema
public class HappyCinema { public static void main(String[] args) { Cinema c = new Cinema(2,"happy sxt"); new Thread(new Customer(c,2),"fairly tall").start(); new Thread(new Customer(c,1),"Lao Pei").start(); } } //customer class Customer implements Runnable{ Cinema cinema; int seats; public Customer(Cinema cinema, int seats) { this.cinema = cinema; this.seats = seats; } @Override public void run() { synchronized(cinema) { boolean flag = cinema.bookTickets(seats); if(flag) { System.out.println("Ticket issued successfully"+Thread.currentThread().getName()+"-<Location is:"+seats); }else { System.out.println("Ticket issuing failed"+Thread.currentThread().getName()+"-<Insufficient position"); } } } } //cinema class Cinema{ int available; //Available locations String name; //name public Cinema(int available, String name) { this.available = available; this.name = name; } //Ticket purchase public boolean bookTickets(int seats) { System.out.println("Available locations are:"+available); if(seats>available) { return false; } available -=seats; return true; } }
public class HappyCinema2 { public static void main(String[] args) { //Available location List<Integer> available =new ArrayList<Integer>(); available.add(1); available.add(2); available.add(3); available.add(6); available.add(7); //Location required by customers List<Integer> seats1 =new ArrayList<Integer>(); seats1.add(1); seats1.add(2); List<Integer> seats2 =new ArrayList<Integer>(); seats2.add(3); seats2.add(6); SxtCinema c = new SxtCinema(available,"happy sxt"); new Thread(new HappyCustomer(c,seats1),"fairly tall").start(); new Thread(new HappyCustomer(c,seats2),"Lao Pei").start(); } } //customer class HappyCustomer implements Runnable{ SxtCinema cinema; List<Integer> seats; public HappyCustomer(SxtCinema cinema, List<Integer> seats) { this.cinema = cinema; this.seats = seats; } @Override public void run() { synchronized(cinema) { boolean flag = cinema.bookTickets(seats); if(flag) { System.out.println("Ticket issued successfully"+Thread.currentThread().getName()+"-<Location is:"+seats); }else { System.out.println("Ticket issuing failed"+Thread.currentThread().getName()+"-<Insufficient position"); } } } } //cinema class SxtCinema{ List<Integer> available; //Available locations String name; //name public SxtCinema(List<Integer> available, String name) { this.available = available; this.name = name; } //Ticket purchase public boolean bookTickets(List<Integer> seats) { System.out.println("Welcome"+this.name+",Currently available location is:"+available); List<Integer> copy = new ArrayList<Integer>(); copy.addAll(available); //subtract copy.removeAll(seats); //Judge size if(available.size()-copy.size() !=seats.size()) { return false; } //success available = copy; return true; } }
-
Simulated withdrawal
Account class
class Account{ int money; //amount of money String name; //name public Account(int money, String name) { this.money = money; this.name = name; } }
/** * Thread safety: ensure the correctness and efficiency of data during concurrency * synchronized * 1,Synchronization method * 2,Synchronization block, more targeted * @author azzhu * */ public class SynBlockTest01 { public static void main(String[] args) { //account Account account =new Account(1000,"Wedding gift"); SynDrawing you = new SynDrawing(account,80,"Sad you"); SynDrawing wife = new SynDrawing(account,90,"happy Her"); you.start(); wife.start(); } } //Simulated withdrawal thread security class SynDrawing extends Thread{ Account account ; //Withdrawal account int drawingMoney ;//Amount of money withdrawn int packetTotal ; //Total number of pockets public SynDrawing(Account account, int drawingMoney,String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } @Override public void run() { test() ; } //Target lock account public void test() { //Improve performance if(account.money<=0) { return ; } //Synchronization block synchronized(account) { if(account.money -drawingMoney<0) { return; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } account.money -=drawingMoney; packetTotal +=drawingMoney; System.out.println(this.getName()+"-->The account balance is:"+account.money); System.out.println(this.getName()+"-->The money in the pocket is:"+packetTotal); } } }
/** * Ensure the safety of data concurrency as high as possible * synchronized * 1,Synchronization method * 2,Synchronization block * @author azzhu * */ public class SynTest02 { public static void main(String[] args) { //account Account account =new Account(100,"Wedding gift"); SafeDrawing you = new SafeDrawing(account,80,"Sad you"); SafeDrawing wife = new SafeDrawing(account,90,"happy Her"); you.start(); wife.start(); } } //Simulated withdrawal class SafeDrawing extends Thread{ Account account ; //Withdrawal account int drawingMoney ;//Amount of money withdrawn int packetTotal ; //Total number of pockets public SafeDrawing(Account account, int drawingMoney,String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } @Override public void run() { } //Failed to lock the wrong target. this is not a lock. this should lock the account public synchronized void test() { if(account.money -drawingMoney<0) { return; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } account.money -=drawingMoney; packetTotal +=drawingMoney; System.out.println(this.getName()+"-->The account balance is:"+account.money); System.out.println(this.getName()+"-->The money in the pocket is:"+packetTotal); } }
/** * Thread unsafe: withdraw money * * @author azzhu * */ public class UnsafeTest02 { public static void main(String[] args) { //account Account account =new Account(100,"Wedding gift"); Drawing you = new Drawing(account,80,"Sad you"); Drawing wife = new Drawing(account,90,"happy Her"); you.start(); wife.start(); } } //Simulated withdrawal class Drawing extends Thread{ Account account ; //Withdrawal account int drawingMoney ;//Amount of money withdrawn int packetTotal ; //Total number of pockets public Drawing(Account account, int drawingMoney,String name) { super(name); this.account = account; this.drawingMoney = drawingMoney; } @Override public void run() { if(account.money -drawingMoney<0) { return; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } account.money -=drawingMoney; packetTotal +=drawingMoney; System.out.println(this.getName()+"-->The account balance is:"+account.money); System.out.println(this.getName()+"-->The money in the pocket is:"+packetTotal); } }
2.6 common methods of threading
-
yield vs join
① yield method: comity, but not necessarily success; join, jump the queue
② yield is the static method, which is called thread yield, but join is not a static method
2.6.1 yeild
- 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, ignore this method, that is, the current thread will resume execution immediately at this time!
public class YieldDemo01 { public static void main(String[] args) { MyYield my =new MyYield(); new Thread(my,"a").start(); new Thread(my,"b").start(); } } class MyYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"-->start"); Thread.yield(); //Comity System.out.println(Thread.currentThread().getName()+"-->end"); } }
public class YieldDemo02 { public static void main(String[] args) { new Thread(()->{ for(int i=0;i<100;i++) { System.out.println("lambda...."+i); } }) .start(); for(int i=0;i<100;i++) { if(i%20==0) { Thread.yield(); //main comity } System.out.println("main...."+i); } } }
2.6.2 sleep
Static method in milliseconds
① Sleep has nothing to do with the lock. When the thread's sleep expires, it wakes up automatically and returns to the Runnable state
② The time specified in sleep() is the shortest time that the thread will not run. Therefore, the sleep() method does not guarantee that the thread will resume after its sleep expires
Start to execute immediately [depends on whether the CPU is dispatched immediately]
③ 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.
Analog Countdown:
import java.text.SimpleDateFormat; import java.util.Date; /** * sleep Analog countdown * * @author azzhu * */ public class BlockedSleep03 { public static void main(String[] args) throws InterruptedException { //count down Date endTime=new Date(System.currentTimeMillis()+1000*10); long end = endTime.getTime(); while(true) { System.out.println(new SimpleDateFormat("mm:ss").format(endTime)); Thread.sleep(1000); endTime=new Date(endTime.getTime()-1000); if(end-10000 >endTime.getTime() ) { break; } } } public static void test() throws InterruptedException { //Count down to 10, one in one second int num = 10; while(true) { Thread.sleep(1000); System.out.println(num--); } } }
Rest simulation:
/** * sleep Simulated rest * * @author azzhu * */ public class BlockedSleep02 { public static void main(String[] args) { Racer racer = new Racer(); new Thread(racer,"tortoise").start(); new Thread(racer,"rabbit").start(); } } class Racer implements Runnable{ private String winner;//winner @Override public void run() { for(int steps =1;steps<=100;steps++) { //Simulated rest if(Thread.currentThread().getName().equals("rabbit") && steps%10==0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"-->"+steps); //Is the game over boolean flag = gameOver(steps); if(flag) { break; } } } private boolean gameOver(int steps) { if(winner!=null) { //There is a winner return true; }else { if(steps ==100) { winner = Thread.currentThread().getName(); System.out.println("winner==>"+winner); return true; } } return false; } }
Analog network delay:
/** * sleep Simulate network delay, amplifying the possibility of problems * * @author azzhu * */ public class BlockedSleep01 { public static void main(String[] args) { //A resource Web12306 web =new Web12306(); System.out.println(Thread.currentThread().getName()); //Multiple agents new Thread(web,"Code livestock").start(); new Thread(web,"Code farmer").start(); new Thread(web,"Codehead").start();; } } class Web12306 implements Runnable{ //Number of votes private int ticketNums = 99; @Override public void run() { while(true) { if(ticketNums<0) { break; } //Analog delay try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--); } } }
2.6.3 join
Which thread invokes the join method will block other threads, so that the current thread can execute other [forced queue jumping, interview] after execution
Usage: thread A executes the join method of thread B. thread A must wait for B to complete execution before thread A can continue its work.
public class UseJoin { static class JumpQueue implements Runnable { private Thread thread; //Thread used to jump the queue public JumpQueue(Thread thread) { this.thread = thread; } @Override public void run() { try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" terminated.."); } } public static void main(String[] args) { Thread previous = Thread.currentThread(); //Main thread for (int i = 0; i < 10; i++) { //i=0,previous is the main thread; i=1,previous is the thread i=0 Thread thread = new Thread(new JumpQueue(previous),String.valueOf(i)); System.out.println(previous.getName()+" jump a queue the thread:"+thread.getName()); thread.start(); previous = thread; } //Sleep for 2 seconds SleepTools.second(2); System.out.println(Thread.currentThread().getName()+" terminated..."); } }
public class BlockedJoin01 { public static void main(String[] args) throws InterruptedException { Thread t=new Thread(()->{ for(int i=0;i<100;i++) { System.out.println("lambda...."+i); } }); t.start(); for(int i=0;i<100;i++) { if(i==20) { t.join(); //Queue jumping main blocked } System.out.println("main...."+i); } } }
public class BlockedJoin02 { public static void main(String[] args) throws InterruptedException { System.out.println("The story of father and son buying cigarettes"); new Thread(new Father()).start(); } } class Father extends Thread{ public void run() { System.out.println("I wanted to smoke, but I didn't find it"); System.out.println("Let my son buy Zhonghua"); Thread t =new Thread(new Son()); t.start(); try { t.join(); //father is blocked System.out.println("Dad took the cigarette and gave the change to his son"); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("The child was lost, and dad went out to find the child..."); } } } class Son extends Thread{ public void run() { System.out.println("Took dad's money and went out..."); System.out.println("There is a game hall on the side of the road. I played it for 10 seconds"); for(int i=0;i<10;i++) { System.out.println(i+"Seconds have passed..."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Hurry to buy cigarettes...."); System.out.println("I went home with a bag of Zhonghua in my hand...."); } }
2.6.4 priority
setPriority(1-10): set the priority. Only the probability of priority execution is guaranteed, not necessarily priority. The default is 5, the minimum is 1, and the maximum is 10
The set value must be between 1-10, otherwise the IllegalArgumentException will be thrown
Threads with high priority allocate more time slices than threads with low priority
2.6.5 other methods
- Thread.currentThread.getName()/getId(): get the thread name or id
- public State getState(): get the state of the thread
- public final native boolean isAlive(): judge whether the thread is alive
- public final boolean isDaemon(): judge whether it is a daemon thread
2.6.6 how does calling yield(), sleep(), wait(), notify() and other methods affect locks
Interview point
- After the thread executes yield(), the lock held by the thread is not released
- After the sleep() method is called, the lock held is not released
- Before calling the method, you must hold the lock. After calling the wait() method, the lock will be released. When the wait() method returns, the thread will hold the lock again
- Before calling the method, you must hold the lock. Calling the notify() method itself will not release the lock
2.7 how to terminate a thread
① stop(): obsolete, not recommended, because using stop, even if you add synchronized in your operation, it may lead to data inconsistency
② interrupt(): interrupt thread
③ It can be realized by using the idea of markup
/** * Terminate thread * 1,Number of times the thread has completed normal execution -- > * 2,External interference -- > Add identification * Do not use stop destroy * * @author azzhu * */ public class TerminateThread implements Runnable { //1. Mark whether the thread body can run private boolean flag = true; private String name; public TerminateThread(String name) { this.name = name; } @Override public void run() { int i=0; //2. Association ID, true -- > run, false -- > stop while(flag) { System.out.println(name+"-->"+i++); } } //3. Identification of method change provided externally public void terminate() { this.flag = false; } public static void main(String[] args) { TerminateThread tt = new TerminateThread("C Luo"); new Thread(tt).start(); for(int i=0;i<=99;i++) { if(i==88) { tt.terminate();//Thread termination System.out.println("tt game over"); } System.out.println("main-->"+i); } } }
isInterrupted: if the thread has been interrupted, return true; otherwise, return false
Interrupted: judge whether the current thread is in the interrupted state. We can execute the business according to true and false. This method is a static method. In fact, it calls the isInterrupted method. The source code is as follows
public static boolean interrupted() { return currentThread().isInterrupted(true); }
public class StopThread extends Thread { private int i = 0, j = 0; @Override public void run() { synchronized (this) { // Add synchronization lock to ensure thread safety ++i; try { // Sleep for 10 seconds to simulate time-consuming operation Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } ++j; } } /** * Print i and j */ public void print() { System.out.println("i=" + i + " j=" + j); } }
/** * Example 3 - thread stop forcibly aborts and destroys thread safety */ public class Demo3 { public static void main(String[] args) throws InterruptedException { StopThread thread = new StopThread(); thread.start(); // Sleep for 1 second to ensure that the self increment of i variable is successful Thread.sleep(1000); // Pause thread //thread.stop(); // Erroneous termination thread.interrupt(); // Correct termination while (thread.isAlive()) { // Ensure that the thread has terminated } // Output results thread.print(); } }
/** Judge by status bit */ public class Demo4 extends Thread { public volatile static boolean flag = true; public static void main(String[] args) throws InterruptedException { new Thread(() -> { try { while (flag) { // Determine whether to run System.out.println("In operation"); Thread.sleep(1000L); } } catch (InterruptedException e) { e.printStackTrace(); } }).start(); // After 3 seconds, change the status flag to False, which means that the operation will not continue Thread.sleep(3000L); flag = false; System.out.println("End of program operation"); } }
3. Wait for wake-up mechanism [Master the principle]
[interview] use two threads to realize alternate printing of odd and even numbers or ABAB... Printing
thread-0 1/A
thread-1 2/B
...
Knowledge points involved: lock, wait(), wake-up mechanism (notify(), notifyAll())
public class ThreadTest3 { public static void main(String[] args) { Counter counter = new Counter(); new Thread(new PrintOdd(counter)).start(); new Thread(new PrintEven(counter)).start(); } } class Counter { public int value = 1; public boolean odd = true; } class PrintOdd implements Runnable { public Counter counter; public PrintOdd(Counter counter) { this.counter = counter; } @Override public void run() { while (counter.value <= 100) { synchronized(counter) { if (counter.odd) { System.out.println(counter.value); counter.value++; counter.odd = !counter.odd; //It is important to wake up the even number of printing threads counter.notify(); } try { counter.wait(); } catch (InterruptedException e) {} } } } } class PrintEven implements Runnable { public Counter counter; public PrintEven(Counter counter) { this.counter = counter; } @Override public void run() { while (counter.value <= 100) { synchronized (counter) { if (!counter.odd) { System.out.println(counter.value); counter.value++; counter.odd = !counter.odd; counter.notify(); } try { counter.wait(); } catch (InterruptedException e) {} } } } }
public class Main{ static class Word { String s; public Word(String a) { s = a; } public void setS (String a) { s = a; } public String getS() { return s; } } static int i = 0; static Word s = new Word("A"); public static void main(String[] args) { //A thread Thread t1 = new Thread(new Runnable() { @Override public void run() { while (i < 100) { synchronized (s) { if (s.getS().equals("B")) { try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println(s.getS()); s.setS("B"); i++; s.notify(); } } } } }); //B thread Thread t2 = new Thread(new Runnable() { @Override public void run() { while (i < 100) { synchronized (s) { if (s.getS().equals("A")) { try { s.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println(s.getS()); s.setS("A"); i++; s.notify(); } } } } }); t1.start(); t2.start(); } }
Exercise: print 1-100 using two threads. Thread 1, thread 2
class Test { public static void main(String[] args) { Communication comm = new Communication(); new Thread(comm).start(); new Thread(comm).start(); } } class Communication implements Runnable { int i = 1; public void run() { while (true) { synchronized (this) { notify(); if (i <= 100) { System.out.println(Thread.currentThread().getName() + ":" + i++); } else break; try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
3.1 thread communication
Concept: multiple threads are processing the same resource, but the processing actions (tasks of threads) are different.
For example, thread A is used to produce steamed stuffed buns and thread B is used to eat steamed stuffed buns. Steamed stuffed buns can be understood as the same resource. The actions processed by thread A and thread B are production and consumption, so there is A thread communication problem between thread A and thread B
Why handle inter thread communication:
When multiple threads execute concurrently, the CPU switches threads randomly by default. When we need multiple threads to complete a task together, and we
I hope they can execute regularly, so some coordinated communication is needed between multiple threads to help us achieve the common operation of multiple threads on a piece of data.
How to ensure inter thread communication and make effective use of resources:
When multiple threads are dealing with the same resource and different tasks, thread communication is needed to help solve the use or operation of the same variable between threads. That is, multiple threads avoid competing for the same shared variable when operating the same data. That is, we need to use certain means to make each thread make effective use of resources. This means is the waiting wake-up mechanism.
3.2 waiting for wake-up mechanism
What is the waiting wake-up mechanism
This is a collaboration mechanism between multiple threads. When it comes to threads, we often think of the race between threads, such as competing for locks, but this is not the whole story. There will also be a cooperation mechanism between threads. Just like you and your colleagues in the company, you may have competition for promotion, but more often you work together to complete certain tasks.
That is, after a thread has performed the specified operation, it enters the waiting state (wait()) and wakes up after other threads have executed their specified code (notify()); When there are multiple threads waiting, you can use notifyAll() to wake up all waiting threads if necessary.
wait/notify is a cooperative mechanism between threads.
Method of waiting for wake-up
The wake-up waiting mechanism is used to solve the problem of inter thread communication. The meanings of the three methods used are as follows:
- Wait: the thread is no longer active, no longer participates in scheduling, and enters the wait set. Therefore, CPU resources will not be wasted and lock competition will not occur. At this time, the thread state is WAITING. It also waits for other threads to perform a special action, that is, to "notify" the threads WAITING on this object to be released from the wait set and re-enter the ready queue
-
notify: select a thread in the wait set of the notified object to release; For example, when a restaurant has a free seat, the customer waiting for the longest meal takes the first seat.
-
notifyAll: release all threads on the wait set of the notified object.
Details of calling wait and notify methods
- The wait method and notify method must be called by the same lock object. Because: the corresponding lock object can wake up the thread after using the wait method called by the same lock object through notify.
- The wait method and notify method belong to the methods of Object class. Because: the lock Object can be any Object, and the class of any Object inherits the Object class.
- The wait method and notify/notifyAll method must be used in the synchronization code block or synchronization method. Because: these two methods must be called through the lock object.
3.3 producer and consumer issues
The waiting wake-up mechanism is actually a classic problem of "producers and consumers".
Take the production of steamed stuffed buns and the consumption of steamed stuffed buns as an example. How can the waiting wake-up mechanism make effective use of resources:
Steamed stuffed bun shop threads produce steamed stuffed buns, and eating threads consume steamed stuffed buns. When there is no steamed stuffed bun (the status of steamed stuffed bun is false),The eating thread waits, and the steamed stuffed bun shop thread produces steamed stuffed buns (That is, the status of steamed stuffed bun is true),And notify the eating thread (release the waiting state of eating),Because there are already steamed stuffed buns, the steamed stuffed buns shop thread enters the waiting state. Next, whether the eating thread can further execute depends on the acquisition of the lock. If the food gets the lock, the action of eating steamed stuffed buns will be executed, and the steamed stuffed buns will be finished (bag) Sub status is false),And notify the thread of the baozi shop (release the waiting state of the baozi shop),The eating thread is waiting. If the package shop thread can be further executed, it is taken It depends on the acquisition of the lock.
package test03; /** * Producer and consumer issues * * @author azzhu * @create 2019-12-24 15:56:15 */ public class pc { public static void main(String[] args) { //Waiting for wake-up cases BaoZi bz = new BaoZi(); ChiHuo ch = new ChiHuo("foodie",bz); BaoZiPu bzp = new BaoZiPu("Steamed stuffed bun shop",bz); ch.start(); bzp.start(); } } //shared resource class BaoZi { String pier; String xianer; boolean flag = false;//Whether the package sub resource has package sub resource status } //consumer class ChiHuo extends Thread { private BaoZi bz; public ChiHuo(String name, BaoZi bz) { super(name); this.bz = bz; } @Override public void run() { while (true) { synchronized (bz) { if (!bz.flag) {//No steamed stuffed bun try { bz.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("The food is eating" + bz.pier + bz.xianer + "steamed stuffed bun"); bz.flag = false; bz.notify(); } } } } //producer class BaoZiPu extends Thread { //Operating resources private BaoZi bz; public BaoZiPu(String name, BaoZi bz) { super(name); this.bz = bz; } @Override public void run() { int count = 0; //Steamed stuffed bun while (true) { //synchronization synchronized (bz) { if (bz.flag) {//Package resource exists try { //Producer waiting bz.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // There are no steamed buns to make steamed buns System.out.println("The steamed stuffed bun shop began to make steamed stuffed buns"); if (count % 2 == 0) { // Ice skin five kernel bz.pier = "Ice skin"; bz.xianer = "Wuren"; } else { // Thin skinned beef and scallion bz.pier = "Thin skin"; bz.xianer = "Beef and scallion"; } count++; //modify state bz.flag = true; System.out.println("The steamed stuffed bun is made:" + bz.pier + bz.xianer); System.out.println("Let's eat"); //Wake up waiting thread (eating) bz.notifyAll(); } } } }
3.4 practice
3.4.1 production products
- 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, he 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.
Salesperson category:
class Clerk { // salesperson private int product = 0; public synchronized void addProduct() { if (product >= 20) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { product++; System.out.println("The producer produced the second product" + product + "Products"); notifyAll(); } } public synchronized void getProduct() { if (this.product <= 0) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { System.out.println("The consumer took the second" + product + "Products"); product--; notifyAll(); } } }
Producer class:
class Productor implements Runnable { // producer Clerk clerk; public Productor(Clerk clerk) { this.clerk = clerk; } public void run() { System.out.println("Producers began to produce products"); while (true) { try { Thread.sleep((int) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } clerk.addProduct(); } } }
Consumer category:
class Consumer implements Runnable { // consumer Clerk clerk; public Consumer(Clerk clerk) { this.clerk = clerk; } public void run() { System.out.println("Consumers began to take away products"); while (true) { try { Thread.sleep((int) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } clerk.getProduct(); } } }
Test class:
public class ProductTest { public static void main(String[] args) { Clerk clerk = new Clerk(); Thread productorThread = new Thread(new Productor(clerk)); Thread consumerThread = new Thread(new Consumer(clerk)); productorThread.start(); consumerThread.start(); } }
3.4.2 simulated bank withdrawal
1. Define an Account class
1) The Account class encapsulates two attributes: Account number (String) and balance (double)
2) Set the getter and setter methods of the corresponding properties
3) Provides a constructor with the no participation and two parameters
4) The system judges whether it matches the user according to the account number. It needs to provide rewriting of hashCode() and equals() methods
2. Two thread classes for withdrawing money are provided: Xiaoming and Xiaoming's wire
1) The account attribute of the account class and the withdrawal amount attribute of the double class are provided
2) Provide constructor with thread name
3) The operation of withdrawing money is provided in the run() method
3. Create a thread in the main class for testing. Consider thread safety issues.
Account class:
class Account { private String accountId; private double balance; public Account() { } public Account(String accountId, double balance) { this.accountId = accountId; this.balance = balance; } public String getAccountId() { return accountId; } public void setAccountId(String accountId) { this.accountId = accountId; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public String toString() { return "Account [accountId=" + accountId + ",balance=" + balance + "]"; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((accountId == null) ? 0 : accountId.hashCode()); long temp; temp = Double.doubleToLongBits(balance); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Account other = (Account) obj; if (accountId == null) { if (other.accountId != null) return false; } else if (!accountId.equals(other.accountId)) return false; if (Double.doubleToLongBits(balance) != Double.doubleToLongBits(other.balance)) return false; return true; } }
Withdrawal thread:
class WithDrawThread extends Thread { Account account; // Amount to withdraw double withDraw; public WithDrawThread(String name, Account account, double amt) { super(name); this.account = account; this.withDraw = amt; } public void run() { synchronized (account) { if (account.getBalance() > withDraw) { System.out.println(Thread.currentThread().getName() + ":The withdrawal is successful, and the amount withdrawn is:" + withDraw); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } account.setBalance(account.getBalance() - withDraw); } else { System.out.println("Withdrawal failed when the cash withdrawal limit exceeds the account balance"); } System.out.println("The current balance of the account is:" + account.getBalance()); } } }
Test class:
public class WithDrawThreadTest { public static void main(String[] args) { Account account = new Account("1234567", 10000); Thread t1 = new WithDrawThread("Xiao Ming", account, 8000); Thread t2 = new WithDrawThread("Xiao Ming's wife", account, 2800); t1.start(); t2.start(); } }
3.5 Case Supplement
3.5.1 tube pass method
/** * Collaboration model: producer consumer implementation mode 1: management method * With buffer * * @author azzhu * */ public class CoTest01 { public static void main(String[] args) { 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() { //production for(int i=0;i<100;i++) { System.out.println("production-->"+i+"A steamed bun"); container.push(new Steamedbun(i) ); } } } //consumer class Consumer extends Thread{ SynContainer container ; public Consumer(SynContainer container) { this.container = container; } public void run() { //consumption for(int i=0;i<100;i++) { System.out.println("consumption-->"+container.pop().id+"A steamed bun"); } } } //buffer class SynContainer{ Steamedbun[] buns = new Steamedbun[10]; //Storage container int count = 0; //Counter //Storage production public synchronized void push(Steamedbun bun) { //When can production containers exist //Can not produce only wait if(count == buns.length) { try { this.wait(); //Thread blocking consumer notifies production release } catch (InterruptedException e) { } } //There is room for production buns[count] = bun; count++; //There is data, you can notify the consumer this.notifyAll(); } //Obtain consumption public synchronized Steamedbun pop() { //When is there data in the consumption container //No data, just wait if(count == 0) { try { this.wait(); //Thread blocking producer notifies consumption cancellation } catch (InterruptedException e) { } } //Existing data can be consumed count --; Steamedbun bun = buns[count] ; this.notifyAll(); //There is room to awaken each other's production return bun; } } //Steamed buns class Steamedbun{ int id; public Steamedbun(int id) { this.id = id; } }
3.5.2 signal lamp method
/** * Collaboration model: producer consumer implementation mode 2: signal lamp method * With the help of flag bit * * @author azzhu * */ public class CoTest02 { 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<20;i++) { if(i%2==0) { this.tv.play("Let's Talk"); }else { this.tv.play("It's too dirty. Drink a bottle of Libai and wash your mouth"); } } } } //Consumer audience class Watcher extends Thread{ Tv tv; public Watcher(Tv tv) { this.tv = tv; } public void run() { for(int i=0;i<20;i++) { tv.watch(); } } } //Same resource TV class Tv{ String voice; //Signal lamp //T means the actor performs and the audience waits //F means the audience watches the actors wait boolean flag = true; //perform public synchronized void play(String voice) { //Actor waiting if(!flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //perform System.out.println("Performed:"+voice); this.voice = voice; //awaken this.notifyAll(); //Switch flag this.flag =!this.flag; } //watch public synchronized void watch() { //Audience waiting if(flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //watch System.out.println("Yes:"+voice); //awaken this.notifyAll(); //Switch flag this.flag =!this.flag; } }
4. Thread pool [Extension]
JDK5.0: add creation method 2
4.1 overview of thread pool idea
When we use threads, we create a thread, which is very easy to implement, but there will be a problem:
If there are a large number of concurrent threads and each thread executes a task for a short time, the efficiency of the system will be greatly reduced because it takes time to create and destroy threads frequently.
So is there a way to make threads reusable, that is, after executing a task, they can continue to execute other tasks without being destroyed?
In Java, this effect can be achieved through thread pool. Today, let's talk about java thread pool in detail.
Thread pool concept 2.4
Thread pool: in fact, it is a container containing multiple threads, in which threads can be used repeatedly, eliminating the operation of frequently creating thread objects and consuming too many resources without repeatedly creating threads.
Since many operations in the thread pool are related to optimizing resources, we won't repeat them here. Let's understand the working principle of thread pool through a diagram:
Rational use of thread pool can bring three benefits: [interview]
- **Reduce resource consumption** The number of threads created and destroyed is reduced. Each working thread can be reused and can perform multiple tasks.
- Improve response speed (reduce the time to create new threads). When the task arrives, the task can be executed immediately without waiting for the thread to be created.
- **Improve thread manageability** You can adjust the number of work line threads in the thread pool according to the bearing capacity of the system to prevent excessive internal consumption
Save, and lay down the server (each thread needs about 1MB of memory. The more threads open, the more memory they consume, and finally crash).
Thread pool applications:
- Threads are short and take a lot of time to complete
- Demanding on Performance
- Accept a sudden large number of requests
4.3 source code of thread pool
In fact, the thread pool we create is created by calling ThreadPoolExecutor, so if we customize the thread pool, we need to connect it with ` ` ThreadPoolExecutor '.
The top-level interface of thread pool in Java is Java util. concurrent. Executor, but strictly speaking, executor is not a thread pool, but a tool for executing threads. The real thread pool interface is Java util. concurrent. ExecutorService.
Configuring a thread pool is complex, especially when the principle of thread pool is not very clear, it is likely that the configured thread pool is not better, so in Java util. concurrent. Executors thread factory class provides some static factories to generate some common thread pools. It is officially recommended to use the * * executors * * project class to create thread pool objects.
There is a method to create thread pool in Executors class as follows:
- public static ExecutorService newFixedThreadPool(int nThreads): returns the thread pool object. (a bounded process pool is created, that is, the maximum number of threads in the pool can be specified)
- public static ExecutorService newCachedThreadPool(): the most used and cacheable thread pool
- public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize): schedulable thread pool
- public static ExecutorService newSingleThreadExecutor(): not used much
- Public static executorservice newworksealingpool(): jdk8 NEW
Source code [the first four, when called, are finally new ThreadPoolExecutor]:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { 1. int corePoolSize: This parameter is the core working thread of the thread pool. Just like going to the bank, all its windows are not necessarily open. By default, after the thread pool is created, the number of threads is 0. When a task comes, a thread will be created to execute the task. Let's assume that there are three core Windows, that is, there are six corePoolSize. 2. int maximumPoolSize: This parameter means the maximum number of threads. As mentioned in the above example, the bank has opened a total of six windows, which are the maximum number of threads in the thread pool to work at the same time. The maximum number of windows can work at the same time. 3. BlockingQueue<Runnable> workQueue: This parameter is the blocking queue. When we do business in the bank, not all windows are open. Generally, only a part of the windows are open. If there are many people, they will enter the waiting area of the bank. The thread pool is also designed in this way. This blocking queue is used to store threads that can only wait in the waiting area because the line workspace is occupied. However, when the threads in our waiting area are also full, work tasks are thrown in again, and the thread pool will apply for a new thread again. Just like when the bank waiting area is full, the bank will increase windows in order to improve work efficiency. At this time, open all windows, and the working threads in the thread pool reach the limit, and the subsequent threads will enter the blocking queue. 4.RejectedExecutionHandler handler: This is the rejection policy of the thread pool. When the thread pool has reached the maximum limit and the queue is full, just like the bank, all windows are open and the whole bank is full of people. In order to maintain the safety of the bank, of course, it is necessary to formulate certain policies to deal with the situation that there are many threads. The rejection policy will not be introduced here for the time being. For example, throw an exception, discard directly, and discard the oldest task in the queue. The default is to throw an exception directly 1,CallerRunsPolicy: If you find that the thread pool is still running, run the thread directly 2,DiscardOldestPolicy: In the waiting queue of the thread pool, take out the header and discard it, and then put the current thread into it. 3,DiscardPolicy: Do nothing 4,AbortPolicy: java By default, an exception is thrown: 5.long keepAliveTime The survival time of redundant idle threads. Just like our bank, due to the large number of people, we open all the remaining windows. If our business has been processed and the tasks in non core threads and queues have been processed, this parameter will be effective at this time. Set it for a period of time. If the tasks in queues and non core threads are completed, If there is no task in this time period, the newly added window, equivalent to our number of non core threads, will be closed slowly until only the number of core threads is left. 6.TimeUnit unit: This parameter represents the unit of the above non idle thread survival time. 7.ThreadFactory threadFactory: It refers to the factory that generates the working threads in the thread pool. It is used to create threads. Generally, it can use the default.
https://blog.csdn.net/weixin_43778179/article/details/93750558
4.4 use
To use the thread object in the thread pool:
- Create a thread pool object.
- Create a Runnable interface subclass object. (task)
- Submit Runnable interface subclass object. (take task)
- Close the thread pool (not normally)
package juc.threadpool; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * @Description * @Author DJZ-WWS * @Date 2019/2/26 16:39 */ public class ThreadPoolTest { public static void main(String[] args) throws InterruptedException { ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 3000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new ThreadPoolExecutor.DiscardOldestPolicy()); Runnable myRunnable = () -> { try { Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + "run"); } catch (InterruptedException e) { e.printStackTrace(); } }; executor.execute(myRunnable); executor.execute(myRunnable); executor.execute(myRunnable); System.out.println("---Start three threads first---"); System.out.println("Number of core threads" + executor.getCorePoolSize()); System.out.println("Number of threads in thread pool" + executor.getPoolSize()); System.out.println("Number of queue tasks" + executor.getQueue().size()); executor.execute(myRunnable); executor.execute(myRunnable); executor.execute(myRunnable); System.out.println("---Open three more threads---"); System.out.println("Number of core threads" + executor.getCorePoolSize()); System.out.println("Number of threads in thread pool" + executor.getPoolSize()); System.out.println("Number of queue tasks" + executor.getQueue().size()); Thread.sleep(8000); System.out.println("----8 Seconds later----"); System.out.println("Number of core threads" + executor.getCorePoolSize()); System.out.println("Number of thread pools" + executor.getPoolSize()); System.out.println("Number of queue tasks" + executor.getQueue().size()); executor.shutdown(); } }
4.5 workflow of line process pool
5.JUC concurrency tool class
5.1 CountdownLatch
5.1.1 function
Make a thread wait for other threads to finish their work before executing. Enhanced version of join
5.1.2 application scenarios
- For example, for the marathon race, the ranking calculation is carried out. The ranking of the contestants must be calculated after running the race. Translated into the advance of Java recognition, it means that N threads execute the operation, and the main thread continues to execute after N sub threads are executed
- When starting various framework services, if the main thread of the application wants to execute the main thread after starting the thread of the framework service and completing the startup of all framework services.
5.1.3 actual combat
await(): used to wait
countDown(): responsible for subtracting 1 from the counter
Source code analysis:
1,CountDownLatch:A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes. In other words, the main thread waits for all other sub threads to complete before proceeding 2,Constructor: CountDownLatch(int count)//Initialize the synchronization counter of count. The main thread will execute downward only when the synchronization counter is 0 Main methods: void await()//The current thread wait counter is 0 boolean await(long timeout, TimeUnit unit)//Unlike the above method, it adds a time limit. void countDown()//Counter minus 1 long getCount()//Gets the value of the counter 3.It has an auxiliary internal class: sync.
package cn.azzhu.ch2.tools; import cn.azzhu.ch1.util.SleepTools; import java.util.concurrent.CountDownLatch; /** * There are 5 initialization threads and 6 deduction points [multiple deductions can be made in one thread, and the deduction number > = number of threads] * After deduction, the main thread and business thread can continue their work * @author azzhu * @create 2019-09-28 21:13:08 */ public class UseCountDownLatch { static CountDownLatch latch = new CountDownLatch(6); //Initialize thread private static class InitThread implements Runnable { @Override public void run() { System.out.println("Thread_"+Thread.currentThread().getId() +" ready init work ...."); latch.countDown(); //After the initialization thread completes its work, countDown() is deducted only once for (int i = 0; i < 2; i++) { System.out.println("Thread_"+Thread.currentThread().getId() +" ......continue do its work"); } } } //Business thread private static class BusiThread implements Runnable { @Override public void run() { try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 3; i++) { System.out.println("BusiThread_"+Thread.currentThread().getId() +" do business ....."); } } } public static void main(String[] args) throws InterruptedException { //Separate initialization thread: initialization is divided into two steps, which need to be deducted twice new Thread(() -> { SleepTools.ms(1); System.out.println("Thread_"+Thread.currentThread().getId() +" ready init work step 1st....."); //TODO latch.countDown(); //Deduct once for each step of initialization System.out.println("begin step 2nd....."); SleepTools.ms(1); System.out.println("Thread_"+Thread.currentThread().getId() +" ready init work step 2nd....."); //TODO latch.countDown(); //Deduct once for each step of initialization }).start(); new Thread(new BusiThread()).start(); for (int i = 0; i <= 3; i++) { Thread thread = new Thread(new InitThread()); thread.start(); } //TODO latch.await(); System.out.println("Main do its work ....."); } }
5.2 CyclicBarrier
5.2.1 function
Let a group of threads reach a barrier and be blocked. When the last thread in the group reaches the barrier, the barrier is open and all blocked threads will continue to run. [gather seven dragon balls]
public CyclicBarrier(int parties, Runnable barrierAction) //When the barrier is open, the tasks defined by CyclicBarrier will be executed
5.2.2 application scenarios
CyclicBarrier can be used in the application scenario of multi-threaded calculation of data and finally merging the calculation results. For example, it is now necessary to calculate the salary details of 10 people within 12 months. You can divide the threads into 10 and calculate the salary of each person respectively. Finally, use barrierAction to integrate the calculation results of these threads to get the final result.
5.2.3 actual combat
package cn.azzhu.ch2.tools; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CyclicBarrier; /** * @author azzhu * @create 2019-09-29 08:46:18 */ public class UseCyclicBarrier { private static CyclicBarrier barrier = new CyclicBarrier(5,new CollectThread()); //A container that holds the working information of a child thread private static ConcurrentHashMap<String,Long> resultMap = new ConcurrentHashMap<>(); public static void main(String[] args) { for (int i = 0; i <= 4 ; i++) { Thread thread = new Thread(new SubThread()); thread.start(); } } //Be responsible for the work after the barrier is opened private static class CollectThread implements Runnable { @Override public void run() { StringBuilder result = new StringBuilder(); for (Map.Entry<String, Long> workResult : resultMap.entrySet()) { result.append("["+workResult.getValue()+"]"); } System.out.println(" the result = " + result); System.out.println("do other business ......"); } } //Worker thread private static class SubThread implements Runnable { @Override public void run() { long id = Thread.currentThread().getId(); //The processing result of the thread itself resultMap.put(Thread.currentThread().getId()+"",id); Random r = new Random(); //Randomly determine whether the worker thread sleeps try { if(r.nextBoolean()) { Thread.sleep(1000+id); System.out.println("Thread_"+id+" .... do something "); } //TODO System.out.println(id+"... is await"); barrier.await(); Thread.sleep(1000+id); System.out.println("Thread_"+id+" .... do its business "); } catch (Exception e) { e.printStackTrace(); } } } }
5.2.4 comparison CountDownLatch
- After a thread of CyclicBarrier runs to the barrier point, the thread immediately stops running. Until all threads reach the barrier point, all threads are awakened and re run in sequence; CountDownLatch means that after a thread runs to a certain point, it just decreases the counter value by one and the thread continues to run;
- CyclicBarrier wakes up all the waiting threads, but the waiting threads are executed in sequence; CountDownLatch is to wake up multiple tasks and execute them preemptively;
- CyclicBarrier is reusable because the internal counter can be reset; CountDownLatch cannot be reused. If the counter value is 0, the CountDownLatch cannot be reused.
- CountDownLatch release is controlled by a third party, and CyclicBarrier release is controlled by a group of threads themselves
- CountDownLatch release condition > = number of threads, CyclicBarrier release condition = number of threads
5.3 Semaphone
5.3.1 function
Controls the number of threads that simultaneously access a particular resource
5.3.2 application scenarios
Used in flow control
5.3.3 actual combat
package cn.azzhu.ch2.tools.semaphore; import cn.azzhu.ch1.pool.SqlConnectImpl; import java.sql.Connection; import java.util.LinkedList; import java.util.concurrent.Semaphore; /** * Implementation of a database connection pool * @author azzhu * @create 2019-09-29 09:36:17 */ public class DBPoolSemaphore { private final static int POOL_SIZE = 10; private final Semaphore useful,useless; //useful indicates available database connections, and useless indicates used database connections public DBPoolSemaphore() { this.useful = new Semaphore(POOL_SIZE); this.useless = new Semaphore(0); } //Container for storing database connections private static LinkedList<Connection> pool = new LinkedList<>(); //Initialize pool static { for (int i = 0; i < POOL_SIZE; i++) { pool.addLast(SqlConnectImpl.fetchConnection()); } } /*Return connection*/ public void returnConn(Connection connection) throws InterruptedException { if(connection != null){ System.out.println("Currently"+useful.getQueueLength()+"Threads waiting for database connection!!!" +"Number of available connections:"+useful.availablePermits()); useless.acquire(); synchronized (pool){ pool.addLast(connection); } useful.release(); } } /*Take the connection from the pool*/ public Connection takeConn() throws InterruptedException { useful.acquire(); Connection conn; synchronized (pool){ conn = pool.removeFirst(); } useless.release(); return conn; } }
package cn.azzhu.ch2.tools.semaphore; import cn.azzhu.ch1.util.SleepTools; import java.sql.Connection; import java.util.Random; /** * @author azzhu * @create 2019-09-29 09:47:18 */ public class AppTest { private static DBPoolSemaphore dbPool = new DBPoolSemaphore(); private static class BusiThread extends Thread{ @Override public void run() { Random r = new Random(); //Make the number of connections held by each thread different long start = System.currentTimeMillis(); try { Connection connection = dbPool.takeConn(); System.out.println("Thread_"+Thread.currentThread().getId() +"_Total time taken to get database connection["+(System.currentTimeMillis()-start)+"]ms"); SleepTools.ms(100+r.nextInt(100)); //Simulate the business operation, and the thread holds the connection query data System.out.println("Query data completed, return the connection!"); dbPool.returnConn(connection); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { for (int i = 0; i < 50; i++) { BusiThread thread = new BusiThread(); thread.start(); } } }
5.4 Exchange
5.4.1 function
It is used for data exchange between two threads and has less practical application
5.4.2 actual combat
package cn.azzhu.ch2.tools; import java.util.HashSet; import java.util.Set; import java.util.concurrent.Exchanger; /** * @author azzhu * @create 2019-09-29 09:57:48 */ public class UseExchange { private static final Exchanger<Set<String>> exchange = new Exchanger<>(); public static void main(String[] args) { new Thread(() -> { Set<String> setA = new HashSet<>(); //Container for storing data try { /*Add data setA.add(...)*/ setA = exchange.exchange(setA); //Swap set /*Process the exchanged data*/ } catch (InterruptedException e) { e.printStackTrace(); } }).start(); new Thread(() -> { Set<String> setB = new HashSet<>(); //Container for storing data try { /*Add data setA.add(...)*/ setB = exchange.exchange(setB); //Swap set /*Process the exchanged data*/ } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } }
6. Thread advanced
6.1 volatile
The lightest synchronization mechanism
- It ensures the visibility when different threads operate on this variable, that is, when a thread modifies the value of a variable, the new value is immediately visible to other threads. (for visibility)
- Instruction reordering is prohibited. (achieve order) to ensure that it does not affect the final result
- volatile can only guarantee the atomicity of a single read / write. i + + this operation cannot guarantee atomicity.
Thread visibility is guaranteed, but atomicity is not guaranteed
The most applicable scenario: only one thread writes and multiple threads read
/** * volatile It is used to ensure data synchronization, that is, visibility */ public class VolatileTest { private volatile static int num = 0; public static void main(String[] args) throws InterruptedException { new Thread(()->{ while(num==0) { //Don't write code here } }) .start(); Thread.sleep(1000); num = 1; } }
/** * Volatile Atomicity of the operation cannot be provided * @author azzhu * @create 2019-09-26 19:47:59 */ public class VolatileUnsafe { private static class VolatileVar implements Runnable { private volatile int a = 0; @Override public void run() { String threadName = Thread.currentThread().getName(); a = a + 1; System.out.println(threadName+":======"+a); SleepTools.ms(100); a = a+1; System.out.println(threadName+":======"+a); } } public static void main(String[] args) { VolatileVar v = new VolatileVar(); Thread t1 = new Thread(v); Thread t2 = new Thread(v); Thread t3 = new Thread(v); Thread t4 = new Thread(v); t1.start(); t2.start(); t3.start(); t4.start(); } }
6.2 ThreadLocal stack closure
Make sure each thread uses its own copy. [exchange space for thread security]
In the connection pool, ThreadLocal is often used to ensure that the connections owned by each thread do not affect each other.
public class UseThreadLocal { static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){ @Override protected Integer initialValue() { return 1; } }; /*Run 3 threads*/ public void startThreadArray() { Thread[] runs = new Thread[3]; for (int i = 0; i < runs.length; i++) { runs[i] = new Thread(new TestThread(i)); } for (Thread run : runs) { run.start(); } } //Test the thread. The job of the thread is to change the value of ThreadLocal variable and write it back. See if threads interact with each other public static class TestThread implements Runnable { int id; TestThread(int id){ this.id = id; } @Override public void run() { System.out.println(Thread.currentThread().getName()+":start"); Integer s = threadLocal.get(); //Get the value of the variable s = s + id; threadLocal.set(s); System.out.println(Thread.currentThread().getName()+":"+threadLocal.get()); } } public static void main(String[] args) { UseThreadLocal test = new UseThreadLocal(); test.startThreadArray(); } }
/** * ThreadLocal:Each thread's own local and local storage area * get/set/initialValue */ public class ThreadLocalTest01 { //private static ThreadLocal<Integer> threadLocal = new ThreadLocal<> (); //Change initialization value /*private static ThreadLocal<Integer> threadLocal = new ThreadLocal<> () { protected Integer initialValue() { return 200; }; };*/ private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()-> 200); public static void main(String[] args) { //Get value System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get()); //Set value threadLocal.set(99); System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get()); new Thread(new MyRun()).start(); new Thread(new MyRun()).start(); } public static class MyRun implements Runnable{ public void run() { threadLocal.set((int)(Math.random()*99)); System.out.println(Thread.currentThread().getName()+"-->"+threadLocal.get()); } } }
/** * ThreadLocal:Each thread has its own data, and the change will not affect other threads */ public class ThreadLocalTest02 { private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()-> 1); public static void main(String[] args) { for(int i=0;i<5;i++) { new Thread(new MyRun()).start(); } } public static class MyRun implements Runnable{ public void run() { Integer left =threadLocal.get(); System.out.println(Thread.currentThread().getName()+"Got it-->"+left); threadLocal.set(left -1); System.out.println(Thread.currentThread().getName()+"Remaining-->"+threadLocal.get()); } } }
6.3 atomic operation CAS
/** * CAS:Compare and exchange */ public class CAS { //stock private static AtomicInteger stock = new AtomicInteger(5); public static void main(String[] args) { for(int i=0;i<5;i++) { new Thread(()->{ //Analog network delay try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Integer left = stock.decrementAndGet(); if(left<1) { System.out.println("It's over..."); return ; } System.out.print(Thread.currentThread().getName()+"Robbed a commodity"); System.out.println("-->Remaining"+left); }) .start(); } } }
6.4 lock
6.4.1 re entrant lock
/** * Reentrant lock: the lock can be used continuously */ public class LockTest01 { public void test() { // Get lock for the first time synchronized(this) { while(true) { // Get the same lock for the second time synchronized(this) { System.out.println("ReentrantLock!"); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { new LockTest01().test(); } }
6.4.2 fair lock and unfair lock
If, in terms of time, the request to obtain the lock first must be satisfied first, the lock is fair; If you are not satisfied, it is unfair.
Generally speaking, the efficiency of unfair locks is higher, and queue jumping is allowed on unfair locks.
The fair lock needs to maintain a queue, and the subsequent thread needs to be locked. Even if the lock is idle, first check whether there are other threads wait ing. If there is one to hang, add it to the back of the queue, and then wake up the thread at the front of the queue. In this case, compared with the unfair lock, it hangs and wakes up once more.
The overhead of thread switching mentioned above is actually the reason why the efficiency of unfair lock is higher than that of fair lock, because unfair lock reduces the probability of thread suspension, and subsequent threads have a certain chance to escape the suspended overhead.
6.4.3 read write lock
ReentrantLock and synchronized are exclusive locks
Read write lock: multiple threads are allowed to access at the same time, but when the write thread accesses, all reads and writes are blocked. It is most suitable for reading more and writing less.
6.4.4 shared lock and exclusive lock
ReentrantLock and synchronized are exclusive locks
7. Practice
-
The bank has an account.
There are two depositors who deposit 3000 yuan into the same account, 1000 yuan each time, and three times. Print the account balance after each deposit.Question: does the program have security problems? If so, how to solve them?
[tips]
1. Specify which codes are multi-threaded running codes, and write the run() method
2. Clarify what is shared data.
3. Specify which statements in the multithreaded running code operate the shared data. -
Use two threads to realize alternate printing of odd and even numbers, or ABAB... Printing
-
Classroom knowledge points of thread
① Thread safety
② Thread communication
③ Tortoise and rabbit race [1km, 20 speed, rabbit sleeping], who wins
public class Racer implements Runnable{ private String winner;//winner @Override public void run() { for(int steps =1;steps<=100;steps++) { //Simulated rest if(Thread.currentThread().getName().equals("rabbit") && steps%10==0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"-->"+steps); //Is the game over boolean flag = gameOver(steps); if(flag) { break; } } } private boolean gameOver(int steps) { if(winner!=null) { //There is a winner return true; }else { if(steps ==100) { winner = Thread.currentThread().getName(); System.out.println("winner==>"+winner); return true; } } return false; } public static void main(String[] args) { Racer racer = new Racer(); new Thread(racer,"tortoise").start(); new Thread(racer,"rabbit").start(); } }
public class CRacer implements Callable<Integer>{ private String winner;//winner @Override public Integer call() throws Exception { for(int steps =1;steps<=100;steps++) { //Simulated rest if(Thread.currentThread().getName().equals("pool-1-thread-1") && steps%10==0) { Thread.sleep(100); } System.out.println(Thread.currentThread().getName()+"-->"+steps); //Is the game over boolean flag = gameOver(steps); if(flag) { return steps; } } return null; } private boolean gameOver(int steps) { if(winner!=null) { //There is a winner return true; }else { if(steps ==100) { winner = Thread.currentThread().getName(); System.out.println("winner==>"+winner); return true; } } return false; } public static void main(String[] args) throws InterruptedException, ExecutionException { CRacer racer = new CRacer(); //Create execution service: ExecutorService ser=Executors.newFixedThreadPool(2); //Submit for execution: Future<Integer> result1 =ser.submit(racer) ; Future<Integer> result2 =ser.submit(racer) ; //Get results: Integer r1 =result1.get(); Integer r2 =result2.get(); System.out.println(r1+"-->"+r2); //Shut down service: ser.shutdownNow(); } }
-
Follow up content
Common class (String [String, two SB S], Random, System, date (jdk8 + old and common, Calendar)) + File class
Stream: file reading and writing
Network programming + reflection / annotation
JDBC: java operation database
Recommendation: the art of concurrent programming
8. Appendix
8.1 SleepTools
/** * Thread sleep helper class * @author azzhu * @create 2019-09-25 22:14:41 */ public class SleepTools { /** * Sleep by second * @param seconds */ public static final void second(int seconds) { try { TimeUnit.SECONDS.sleep(seconds); } catch (InterruptedException e) { e.printStackTrace(); } } /** * Sleep in milliseconds * @param millSeconds */ public static final void ms(int millSeconds) { try { TimeUnit.MILLISECONDS.sleep(millSeconds); } catch (InterruptedException e) { e.printStackTrace(); } } }