JUC concurrency
1. What is JUC
JUC is the toolkit, package and classification under java.util.
Business: common thread code
- Thread
- Runnable has no return value, and its efficiency is relatively lower than that of Callable
- Callable has a return value!
2. Threads and processes
Threads, processes, if you can not use a word out technology, not solid!
- Process: a program, a collection of QQ.exe Music.exe programs;
- A process can often contain multiple threads, at least one!
- Java has 2 threads by default? mian,GC
- Thread: open a process Typora, write, and save automatically (the thread is responsible)
- For Java, it provides Thread, Runnable and Callable operation threads.
Can java really start threads? It won't open
public synchronized void start() { /** * This method is not invoked for the main method thread * or "system" group threads created/set up by the VM. Any new * functionality added to this method in the future may have to * also be added to the VM.A zero status value corresponds to * state "NEW". */ if (threadStatus != 0) throw new IllegalThreadStateException(); /* * Notify the group that this thread is about to be started * so that it can be added to the group's list of threads * and the group's unstarted count can be decremented. */ group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */ } } } // Local methods, the underlying operation is C + +, Java can not directly operate the hardware private native void start0();
Concurrency and parallelism
Concurrent programming: concurrent, parallel
Concurrency (multiple threads operate on the same resource)
- One CPU core simulates multiple threads and alternates quickly
Parallel (multiple people walking together)
- The CPU is multi-core, and multiple threads can be executed at the same time; eg: thread pool!
package demo01; public class Test01 { public static void main(String[] args) { //Gets the number of cores of the CPU //CPU intensive, IO intensive System.out.println(Runtime.getRuntime().availableProcessors()); } }
The essence of concurrent programming: making full use of CPU resources
Threads have several states (6)
public enum State {//State mode /** * Thread state for a thread which has not yet started. */ //newborn NEW, /** * Thread state for a runnable thread. A thread in the runnable * state is executing in the Java virtual machine but it may * be waiting for other resources from the operating system * such as processor. */ //function RUNNABLE, /** * Thread state for a thread blocked waiting for a monitor lock. * A thread in the blocked state is waiting for a monitor lock * to enter a synchronized block/method or * reenter a synchronized block/method after calling * {@link Object#wait() Object.wait}. */ //block BLOCKED, /** * Thread state for a waiting thread. * A thread is in the waiting state due to calling one of the * following methods: * <ul> * <li>{@link Object#wait() Object.wait} with no timeout</li> * <li>{@link #join() Thread.join} with no timeout</li> * <li>{@link LockSupport#park() LockSupport.park}</li> * </ul> * * <p>A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called <tt>Object.wait()</tt> * on an object is waiting for another thread to call * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on * that object. A thread that has called <tt>Thread.join()</tt> * is waiting for a specified thread to terminate. */ //Jam, etc WAITING, /** * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: * <ul> * <li>{@link #sleep Thread.sleep}</li> * <li>{@link Object#wait(long) Object.wait} with timeout</li> * <li>{@link #join(long) Thread.join} with timeout</li> * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> * </ul> */ //Timeout waiting TIMED_WAITING, /** * Thread state for a terminated thread. * The thread has completed execution. */ //termination TERMINATED; }
wait/sleep difference
1. From different classes
- wait => Object
- sleep = > Thread
2. Release of lock
- wait releases the lock
- Sleep will not release the lock, sleep
3. The scope of use is different
- wait must be used in synchronous code blocks
- Sleep can sleep anywhere
4. Need to catch exceptions
- wait does not need to catch exceptions
- sleep must catch exceptions
3.Synchronized lock
Traditional Synchronized lock
Let's take a multi-threaded ticket selling example
package demo01; /* Basic ticket selling examples */ /** * True multithreaded development, development in the company * A thread is a separate resource class without any attached operations * 1.Properties and methods */ public class SaleTicketDemo01 { public static void main(String[] args) { //Concurrency: multiple threads operate on the same resource class and throw the resource class into the thread Ticket ticket = new Ticket(); //@Functional interface functional interface jdk8 lamdba expression (parameter) - > {code} new Thread(() ->{ for (int i =1; i<40;i++){ ticket.sale(); } },"A").start(); new Thread(() ->{ for (int i =1; i<40;i++){ ticket.sale(); } },"B").start(); new Thread(() ->{ for (int i =1; i<40;i++){ ticket.sale(); } },"C").start(); } } //Resource class OOP class Ticket{ //Properties and methods private int number = 50; //How to buy tickets //Essence of synchronized: queue, lock public synchronized void sale(){ if (number >0){ System.out.println(Thread.currentThread().getName() + "Sold" +(number --)+ "ticket,surplus:" + number); } } }
4.LOCK lock (key)
LOCK interface
- Fair lock: very fair, you can come first
- Unfair lock: very unfair. You can jump the queue (default)
Use LOCK to write the column just now
package demo01; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class SaleTicketDemo02 { public static void main(String[] args) { //Concurrency: multiple threads operate on the same resource class and throw the resource class into the thread Ticket2 ticket = new Ticket2(); //@Functional interface functional interface jdk8 lamdba expression (parameter) - > {code} new Thread(() ->{for (int i =1; i<40;i++) ticket.sale();},"A").start(); new Thread(() ->{for (int i =1; i<40;i++) ticket.sale();},"B").start(); new Thread(() ->{for (int i =1; i<40;i++) ticket.sale();},"C").start(); } } /** * 1. new ReentrantLock(); * 2. lock.lock(); //Lock * 3. finally{ * lock.unlock();//Unlock * } */ class Ticket2{ //Properties and methods private int number = 50; //How to buy tickets //LOCK lock Lock lock = new ReentrantLock(); public void sale(){ lock.lock();;//Lock try{ //Business code block if (number >0){ System.out.println(Thread.currentThread().getName() + "Sold" +(number --)+ "ticket,surplus:" + number); } }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock();//Unlock } } }
The difference between synchronized and Lock
1. Synchronized is a built-in Java keyword, and Lock is a Java class
2. Synchronized cannot judge the status of acquiring a lock. Lock can judge the status of acquiring a lock
3. Synchronized will automatically release the Lock, and the Lock must be released manually! If the Lock is not released, it will deadlock
4. Synchronized thread 1 (lock acquisition, blocking), thread 2 (waiting); Lock doesn't have to wait (trylock tries to get the lock)
5. Synchronized reentrant lock, non interruptible, unfair; Lock, reentrant lock, lock judgment, unfair (you can set it yourself)
6. Synchronized is suitable for locking a small number of code synchronization problems, and Lock is suitable for locking a large number of synchronization codes!
What is a lock and how to judge who it is?
5. Producer and consumer issues
Common questions in interview: Singleton mode, sorting algorithm, producers and consumers, deadlock
Synchronized version of producer and consumer issues
package demo02; import sun.awt.windows.ThemeReader; /** Communication between threads: producer and consumer issues Threads execute alternately: A and B operate the same variable num = 0 A num+1 B num-1 */ public class SYProducers { public static void main(String[] args) { Date date = new Date(); //Execute + 1 new Thread(()->{ for (int i =0; i<10;i++){ try { date.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); //Execution - 1 new Thread(()->{ for (int i =0;i<10;i++){ try { date.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); } } //Judgment, waiting, business, notification class Date{//Digital resource class private int number = 0; //+1 public synchronized void increment() throws InterruptedException { if (number !=0){ //wait for this.wait(); } number++; //Notify other threads that I + 1 is over System.out.println(Thread.currentThread().getName() +"=>" + number); this.notifyAll(); } //-1 public synchronized void decrement() throws InterruptedException { if (number == 0){ //wait for this.wait(); } number --; //Notify other threads, I -1 finished System.out.println(Thread.currentThread().getName() +"=>" + number); this.notifyAll(); } }
The problem exists, A B C D 4 threads! spurious wakeup
Change if judgment to while judgment
package demo02; import sun.awt.windows.ThemeReader; /** Communication between threads: producer and consumer issues Threads execute alternately: A and B operate the same variable num = 0 A num+1 B num-1 */ public class SYProducers { public static void main(String[] args) { Date date = new Date(); //Execute + 1 new Thread(()->{ for (int i =0; i<10;i++){ try { date.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); //Execution - 1 new Thread(()->{ for (int i =0;i<10;i++){ try { date.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); new Thread(()->{ for (int i =0; i<10;i++){ try { date.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } },"C").start(); new Thread(()->{ for (int i =0; i<10;i++){ try { date.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } },"D").start(); } } //Judgment, waiting, business, notification class Date{//Digital resource class private int number = 0; //+1 /* Suppose number is equal to 1 at this time, that is, the product has been produced If the if judgment is used here, if two producer threads a and C compete for the execution right of the increment() method Suppose A gets the execution right, and after judgment, number= 0 is established, A.wait() starts to wait (wait() will release the lock), and then C tries to execute the production method, But still judge number= 0 is established, then C.wait() starts to wait (wait() will release the lock) It happens that the consumer thread thread B/D consumes a product at that time, so that number=0 and then B/D will call this.notifyAll() after consumption. At this time, two waiting producer threads continue to produce products, while number + + executes twice Similarly, repeat the above process, the producer thread continues to wait(), and the consumer calls this.notifyAll(); Then producers continue to produce ahead of time, resulting in 'overcapacity', that is, number is greater than 1 if(number != 0){ // wait for this.wait(); }*/ public synchronized void increment() throws InterruptedException { while (number !=0){ //wait for this.wait(); } number++; //Notify other threads that I + 1 is over System.out.println(Thread.currentThread().getName() +"=>" + number); this.notifyAll(); } //-1 public synchronized void decrement() throws InterruptedException { while (number == 0){ //wait for this.wait(); } number --; //Notify other threads, I -1 finished System.out.println(Thread.currentThread().getName() +"=>" + number); this.notifyAll(); } }
Producer and consumer issues of JUC version
A Condition method can be found through Lock
code implementation
package demo02; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LOCKProducers { public static void main(String[] args) { Date2 date = new Date2(); new Thread(()->{ for (int i =0; i<10;i++){ try { date.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); //Execution - 1 new Thread(()->{ for (int i =0;i<10;i++){ try { date.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); new Thread(()->{ for (int i =0; i<10;i++){ try { date.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } },"C").start(); new Thread(()->{ for (int i =0; i<10;i++){ try { date.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } },"D").start(); } } //Judgment, waiting, business, notification class Date2 {//Digital resource class private int number = 0; //+1 Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public void increment() throws InterruptedException { //condition.await();// wait for //condition.signalAll();// Wake up all lock.lock(); try{ while (number != 0) { //wait for condition.await(); } number++; System.out.println(Thread.currentThread().getName() + "=>" + number); condition.signal(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } //-1 public void decrement() throws InterruptedException { lock.lock(); try{ while (number == 0) { //wait for condition.await(); } number--; //Notify other threads, I -1 finished System.out.println(Thread.currentThread().getName() + "=>" + number); condition.signal(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } }
Any new technology is definitely not just covering the original technology, but has its advantages and supplements to the old technology!
Condition accurate notification and wake-up threads
Orderly execution thread
package demo02; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * A Call B after execution, call C after execution, and call A after execution */ public class C { public static void main(String[] args) { Data3 data3 = new Data3(); new Thread(()->{ for (int i =0; i< 10; i++){ data3.printA(); } },"A").start(); new Thread(()->{ for (int i =0; i< 10; i++){ data3.printB(); } },"B").start(); new Thread(()->{ for (int i =0; i< 10; i++){ data3.printC(); } },"C").start(); } } class Data3{//Resource lock private Lock lock = new ReentrantLock(); private Condition condition1 = lock.newCondition(); private Condition condition2 = lock.newCondition(); private Condition condition3 = lock.newCondition(); private int number = 1; public void printA(){ lock.lock(); try{ while(number != 1){ //wait for condition1.await(); } System.out.println(Thread.currentThread().getName() + " => A"); //Wake up the specified B condition2.signal(); number = 2; }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } public void printB(){ lock.lock(); try{ //Business, judgment, execution, notification while(number != 2){ condition2.await(); } System.out.println(Thread.currentThread().getName() + " => B"); condition3.signal(); number = 3; }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } public void printC(){ lock.lock(); try{ while(number != 3){ condition3.await(); } System.out.println(Thread.currentThread().getName() + " => C"); condition1.signal(); number = 1; }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } //Production line: order - > payment operation - > transaction - > Logistics }
6.8 lock phenomenon
The previous question is: how to judge who the lock is! Know what a lock is and who it is!
Deep understanding of our locks
package lock8; import java.util.concurrent.TimeUnit; /* 8 Lock is about 8 questions about lock 1.Under standard conditions, two threads print first, send text messages or make phone calls? 1/sendSms 2/call 2.sendSms Delay 1 second, two threads print first, send text messages or call? 1/sendSms 2/call */ public class Test1 { public static void main(String[] args) { Phone phone = new Phone(); // new Thread(()->{ phone.sendSms(); },"A").start(); // capture try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(()->{ phone.call(); },"B").start(); } } class Phone{ //The object of the synchronized lock is the caller of the method //Both methods use the same lock //Who gets it first, who executes it public synchronized void sendSms(){ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("sendSms"); } public synchronized void call(){ System.out.println("call"); } }
The common method has no lock and is not affected by the results. It can be executed normally
package lock8; import java.util.concurrent.TimeUnit; /** * 3.A common method is added, in which sending text messages is delayed by 4 seconds. Do you want to send text messages first or hello? * 1/hello 2/sendSms * 4.Two objects, two synchronization methods, send text messages first or call first? * 1/call 2/sendSms */ public class Test2 { public static void main(String[] args) { Phone2 phone = new Phone2(); Phone2 phone2 = new Phone2();//Two objects // new Thread(()->{ phone.sendSms(); },"A").start(); // capture try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(()->{ phone2.call(); },"B").start(); } } class Phone2{ //The object of the synchronized lock is the caller of the method //Both methods use the same lock //Who gets it first, who executes it public synchronized void sendSms(){ try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("sendSms"); } public synchronized void call(){ System.out.println("call"); } //There is no lock. It is not a synchronization method and is not affected by the lock public void hello(){ System.out.println("hello"); } }
Static is executed when the class is loaded. The synchronization method with static is class lock
package lock8; import java.util.concurrent.TimeUnit; /** * 5.Add two static synchronization methods. There is only one object. Send text messages first or call first? * 1/sendSms 2/call * 6.Two objects, plus two static synchronization methods, send text messages first or call first? * 1/sendSms 2/call */ public class Test3 { public static void main(String[] args) { Phone3 phone = new Phone3(); Phone3 phone3 = new Phone3(); // new Thread(()->{ phone.sendSms(); },"A").start(); // capture try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(()->{ phone3.call(); },"B").start(); } } class Phone3{ //The object of the synchronized lock is the caller of the method //Both methods use the same lock //Who gets it first, who executes it //Static static method //Class loading public static synchronized void sendSms(){ try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("sendSms"); } public static synchronized void call(){ System.out.println("call"); } }
7 / 8 in both cases, call first and then send text messages. Because the objects of the two locks are different, the static synchronization method locks the Class template, and the ordinary synchronization method locks the instantiated object, so you don't have to wait for the former to unlock before the latter can execute. Instead, the two execute in parallel. Because text messages sleep for 4s, call first
package lock8; import java.util.concurrent.TimeUnit; /** * 6.A common synchronization method, a static synchronization method, only one object, send text messages first and call first? * 1/call 2/sendSms * 7.A common synchronization method, a static synchronization method, two objects, send text messages first and call first? * 1/call 2/sendSms */ public class Test4 { public static void main(String[] args) { Phone4 phone = new Phone4(); Phone4 phone4 = new Phone4(); new Thread(()->{ phone.sendSms(); },"A").start(); // capture try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(()->{ phone4.call(); },"B").start(); } } class Phone4{ //The lock is a Class template //These are two locks public static synchronized void sendSms(){ try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("sendSms"); } //The lock is the caller public synchronized void call(){ System.out.println("call"); } }
Summary
- new: the lock is a specific mobile phone of this
- staic: the lock is the only template of Class
7. The collection class is unsafe
- not safe
package unsafe; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; public class ListTest { /* ArrayList A thread safe variant of, in which all variable operations (add, set, etc.) are implemented by making a new copy of the underlying array. CopyOnWriteArrayList public CopyOnWriteArrayList(Collection<? extends E> c) Create a list containing the specified collection elements in the order in which the collection iterator returns the elements. */ public static void main(String[] args) { //And sending an ArrayList is not safe /** * Solution: * 1.Scheme 1: List < string > List = new vector < > (); * 2.List<String> list = Collections.synchronizedList(Arrays.asList("1", "2", "3")); * 3.List<String> list = new CopyOnWriteArrayList<>(); */ /** CopyOnWriteArrayList Assignment on write is an optimization strategy in the field of COW computer programming; * uoge When the thread calls, the list is read, fixed, and written (overwritten) * Avoid overwriting when writing, resulting in data problems * Read write separation * CopyOnWriteArrayList What's better than Vector? * Copy when writing */ List<String> list = new CopyOnWriteArrayList<>(); for (int i =0; i< 10; i++){ new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(list); },String.valueOf(i)).start(); } } }
Source code: copy when writing
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-xg42kdgz-1634039720370) (C: / users / 77 / appdata / roaming / typora / typora user images / image-20211007101311179. PNG)]
Set is not safe
package unsafe; import java.util.UUID; import java.util.concurrent.CopyOnWriteArraySet; public class SetTest { //java.util.ConcurrentModificationException concurrent modification exception public static void main(String[] args) { /* Solution 1.Set<String> set = Collections.synchronizedSet(new HashSet<>()); 2.CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>(); */ CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>(); for (int i =1; i <=10 ;i ++){ new Thread(()->{ set.add(UUID.randomUUID().toString().substring(0,5)); System.out.println(set); },String.valueOf(i)).start(); } } }
What is the bottom layer of HashSet?
It can be seen that the bottom layer of the HashSet is a HashMap
public boolean add(E e) { return map.put(e, PRESENT)==null; }//The essence of add set is that the key of map cannot be repeated private static final Object PRESENT = new Object();//This is a constant value
Map is not secure
Review the basic operations of map:
package unsafe; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class HashMapTest { public static void main(String[] args) { //Is map used like this? No, you don't use HashMap at work //What is the default equivalent? new HashMap<>(16,0.75) //Map<String,String> map = new HashMap<>();// Thread unsafe //Load factor, initialization capacity Map<String,String> map = new ConcurrentHashMap<>();//security for (int i = 0; i<=30; i++){ new Thread(()->{ map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5)); System.out.println(map); },String.valueOf(i)).start(); } } }
8.Callable (simple)
1. Can have return value
2. Exceptions can be thrown
3. Different methods
Callable vs. Runable
For example, Callable is yourself. You want to know her best friend Thread through your girlfriend * * Runable * *
- Callable is the interface under concurrent under the java.util package. It has a return value and can throw checked exceptions
- Runable is an interface under the java.lang package. It has no return value and cannot throw checked exceptions
- They call different methods, run()/ call()
Similarly, the difference between Lock and Synchronized is that the former is the interface under java.util and the latter is the keyword under java.lang.
How to use Callable?
package callable; import demo02.C; import sun.awt.windows.ThemeReader; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class CallableTest { public static void main(String[] args) throws ExecutionException, InterruptedException { //new Thread(new MyThread()).start(); //new Thread(new FutureTask<>(Callable)).strat(); //How threads start //new an object MyThread myThread = new MyThread(); //Adapt the class so that Callable can be called FutureTask futureTask = new FutureTask<>(myThread); new Thread(futureTask,"A").start(); //Two objects call several calls //One, the results will be cached to improve efficiency, so only one call will be printed new Thread(futureTask,"B").start(); Integer integer = (Integer)futureTask.get();//Get the returned result of Callable / / the get method may block and put it to the last, which communicates asynchronously System.out.println(integer); } } /* class MyThread implements Runnable{ @Override public void run() { } }*/ //< string > represents the required return value class MyThread implements Callable<Integer>{ @Override public Integer call() throws Exception { System.out.println("call()"); return 1024; } }
Details:
1. With cache
2. The result may need to wait and block!
9. Common auxiliary classes (mandatory)
CountDownLatch
Subtraction counter: to trigger a task after calling the thread several times
A synchronization helper class that allows one or more threads to wait until a set of operations are completed in other threads.
package add; import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer; import java.util.concurrent.CountDownLatch; //Counter public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { //The total countdown is 6 CountDownLatch countDownLatch = new CountDownLatch(6); countDownLatch.countDown(); //-1 for (int i =1; i<=6 ; i++){ new Thread(()->{ System.out.println(Thread.currentThread().getName() + "GO out"); countDownLatch.countDown();//-1 },String.valueOf(i)).start(); } countDownLatch.await(); // Wait for the counter to return to zero before executing downward System.out.println("close door"); } }
1GO out 6GO out 4GO out 3GO out 5GO out 2GO out close door
countDownLatch.countDown(); // Quantity - 1
countDownLatch.await(); // Wait for the counter to return to zero before executing downward
Every time a thread calls countDown(), the number is - 1. Assuming that the counter becomes 0, countDownLatch.await() will be awakened and continue to execute!
CyclicBarrier
Addition counter
package add; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class CyclicBarrierDemo { public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{ System.out.println("success"); }); for (int i = 0; i<7;i++){ final int temp = i; //Can lamdba operate to i new Thread(()->{ System.out.println(Thread.currentThread().getName() + "collect" + temp + "A dragon ball"); try{ cyclicBarrier.await();//wait for } catch (BrokenBarrierException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } } }
Thread-0 Collect 0 Dragon Balls Thread-5 Collect 5 dragon balls Thread-4 Collect 4 Dragon Balls Thread-2 Collect 2 Dragon Balls Thread-1 Collect 1 Dragon Ball Thread-3 Collect 3 dragon balls Thread-6 Collect 6 dragon balls success
Semaphore
Semaphore: semaphore
Current restriction / parking space grabbing! 6 cars - 3 parking positions
package add; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; public class SemaphoreDemo { public static void main(String[] args) { //Number of threads: parking spaces Semaphore semaphore = new Semaphore(3); for(int i =0 ;i<6;i++){ new Thread(()->{ try { //acquire obtain //release semaphore.acquire();//get System.out.println(Thread.currentThread().getName()+ "Grab a parking space"); TimeUnit.SECONDS.sleep(2);//Stop for 2 seconds //Leave the parking space System.out.println(Thread.currentThread().getName() + "Leave the parking space"); } catch (InterruptedException e) { e.printStackTrace(); }finally { semaphore.release(); } },String.valueOf(i)).start(); } } }
0 Grab a parking space 3 Grab a parking space 1 Grab a parking space 1 Leave the parking space 0 Leave the parking space 3 Leave the parking space 5 Grab a parking space 2 Grab a parking space 4 Grab a parking space 5 Leave the parking space 2 Leave the parking space 4 Leave the parking space Process finished with exit code 0
semaphore.acquire(); Get, if it is full, wait, wait until it is released!
semaphore.release(); Release, the current semaphore will be released + 1, and then wake up the waiting thread!
Function: mutually exclusive use of multiple shared resources! Concurrent flow restriction, control the maximum number of threads!
10. Read write lockreadwritelock
If the user-defined cache is not locked, there will be a situation where one is not written and the other is suddenly inserted
package add; import java.util.HashMap; import java.util.Map; /** * ReadWriteLock */ public class ReadWriteLock { public static void main(String[] args) { MyCache myCache = new MyCache(); //write in for (int i = 1; i<= 5; i++){ final int temp = i; new Thread(() -> { myCache.put(temp+"",temp+""); },String.valueOf(i)).start(); } //read for (int i = 1; i<= 5; i++){ final int temp = i; new Thread(() -> { myCache.get(temp+""); },String.valueOf(i)).start(); } } } /** * Custom cache */ class MyCache{ private volatile Map<String,Object> map = new HashMap<>(); //Save public void put(String key,Object Value){ System.out.println(Thread.currentThread().getName() + "write in" + key); map.put(key,Value); System.out.println(Thread.currentThread().getName() + "write in OK"); }; //take public void get(String key){ System.out.println(Thread.currentThread().getName() + "read" + key); Object o = map.get(key); System.out.println(Thread.currentThread().getName() + "read OK"); }; }
2 Write 2 5 Write 5 5 write in OK 4 Write 4 4 write in OK 3 Write 3 1 Write 1 3 write in OK 2 write in OK 2 Read 2 1 Read 1 1 write in OK 1 read OK 2 read OK 3 Read 3 5 Read 5 5 read OK 4 Read 4 4 read OK 3 read OK Process finished with exit code 0
Use read / write lock
package add; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * An exclusive lock (write lock) can only be occupied by one thread at a time * Shared lock (read lock) multiple threads can occupy at the same time * ReadWriteLock * Read read can coexist * Read write cannot coexist * Write write cannot coexist * */ public class ReadWriteLock { public static void main(String[] args) { MyCacheLock myCacheLock = new MyCacheLock(); //write in for (int i = 1; i<= 5; i++){ final int temp = i; new Thread(() -> { myCacheLock.put(temp+"",temp+""); },String.valueOf(i)).start(); } //read for (int i = 1; i<= 5; i++){ final int temp = i; new Thread(() -> { myCacheLock.get(temp+""); },String.valueOf(i)).start(); } } } /** * Custom cache */ class MyCache{ private volatile Map<String,Object> map = new HashMap<>(); //Save public void put(String key,Object Value){ System.out.println(Thread.currentThread().getName() + "write in" + key); map.put(key,Value); System.out.println(Thread.currentThread().getName() + "write in OK"); }; //take public void get(String key){ System.out.println(Thread.currentThread().getName() + "read" + key); Object o = map.get(key); System.out.println(Thread.currentThread().getName() + "read OK"); }; } //Locked cache class MyCacheLock{ private volatile Map<String,Object> map = new HashMap<>(); private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();//Read write lock //When writing, you only want one thread to write to it at the same time //Save public void put(String key,Object Value){ lock.writeLock().lock();//Write lock try{ System.out.println(Thread.currentThread().getName() + "write in" + key); map.put(key,Value); System.out.println(Thread.currentThread().getName() + "write in OK"); }catch (Exception e){ e.printStackTrace(); }finally { lock.writeLock().unlock();//Unlock } }; //Everyone can read it //take public void get(String key){ lock.readLock().lock(); try{ System.out.println(Thread.currentThread().getName() + "read" + key); Object o = map.get(key); System.out.println(Thread.currentThread().getName() + "read OK"); }catch (Exception e){ e.printStackTrace(); }finally { lock.readLock().unlock(); } }; }
1 Write 1 1 write in OK 2 Write 2 2 write in OK 3 Write 3 3 write in OK 4 Write 4 4 write in OK 5 Write 5 5 write in OK 1 Read 1 1 read OK 3 Read 3 3 read OK 2 Read 2 2 read OK 5 Read 5 4 Read 4 4 read OK 5 read OK
11. Blocking queue
Blocking queue:
BlockingQueue is not a new thing
Under what circumstances do we use blocking queues: multithreading concurrency and more thread pools
Learn to use queues
Add remove
Four sets of API s
mode | Throw exception | If there is a return value, no exception will be thrown | Blocking wait | Timeout wait |
---|---|---|---|---|
add to | add | offer() | put() | offer(,) |
remove | remove | poll() | take() | poll(,) |
Inspection team head element | element | peek() | - | - |
Exception thrown
package queue; import java.util.concurrent.ArrayBlockingQueue; public class Test { //Collection //list //Set public static void main(String[] args) { test1(); } /** * Throw exception */ public static void test1(){ //Size of queue ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3); System.out.println(arrayBlockingQueue.add("A")); System.out.println(arrayBlockingQueue.add("B")); System.out.println(arrayBlockingQueue.add("C")); //The IllegalStateException threw an exception //System.out.println(arrayBlockingQueue.add("D")); System.out.println("---------------"); System.out.println(arrayBlockingQueue.element());//View elements of team leader System.out.println("---------------"); System.out.println(arrayBlockingQueue.remove());//First in, first out System.out.println(arrayBlockingQueue.remove()); System.out.println(arrayBlockingQueue.remove()); //NoSuchElementException //System.out.println(arrayBlockingQueue.remove()); } }
If there is a return value, no exception is thrown
package queue; import java.util.concurrent.ArrayBlockingQueue; public class Test { //Collection //list //Set public static void main(String[] args) { test2(); } public static void test2(){ ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(3); System.out.println(arrayBlockingQueue.offer("A")); System.out.println(arrayBlockingQueue.offer("B")); System.out.println(arrayBlockingQueue.offer("C"));//true System.out.println("-----------------"); System.out.println(arrayBlockingQueue.peek()); //System.out.println(arrayBlockingQueue.offer("D"));//false does not throw an exception and returns a boolean value System.out.println("-----------------"); System.out.println(arrayBlockingQueue.poll()); System.out.println(arrayBlockingQueue.poll()); System.out.println(arrayBlockingQueue.poll());//It's still first in, first out System.out.println(arrayBlockingQueue.poll());//None does not throw an exception } }
Waiting has been blocked
package queue; import java.util.concurrent.ArrayBlockingQueue; public class Test { //Collection //list //Set public static void main(String[] args) { try { test3(); } catch (InterruptedException e) { e.printStackTrace(); } } /** * Wait, block (always block) */ public static void test3() throws InterruptedException { ArrayBlockingQueue arrayBlockingQueue =new ArrayBlockingQueue(3); //Always blocked arrayBlockingQueue.put("A"); arrayBlockingQueue.put("B"); arrayBlockingQueue.put("C"); //arrayBlockingQueue.put("D");// There is no place in the queue. He will wait all the time System.out.println("----------------"); System.out.println(arrayBlockingQueue.take()); System.out.println(arrayBlockingQueue.take()); System.out.println(arrayBlockingQueue.take()); //System.out.println(arrayBlockingQueue.take()); } }
Timeout wait
package queue; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.TimeUnit; public class Test { //Collection //list //Set public static void main(String[] args) { try { test4(); } catch (InterruptedException e) { e.printStackTrace(); } } /** * Throw exception */ public static void test1(){ //Size of queue ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3); System.out.println(arrayBlockingQueue.add("A")); System.out.println(arrayBlockingQueue.add("B")); System.out.println(arrayBlockingQueue.add("C")); //The IllegalStateException threw an exception //System.out.println(arrayBlockingQueue.add("D")); System.out.println("---------------"); System.out.println(arrayBlockingQueue.element());//View elements of team leader System.out.println("---------------"); System.out.println(arrayBlockingQueue.remove());//First in, first out System.out.println(arrayBlockingQueue.remove()); System.out.println(arrayBlockingQueue.remove()); //NoSuchElementException //System.out.println(arrayBlockingQueue.remove()); } /** * Do not throw exceptions */ public static void test2(){ ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(3); System.out.println(arrayBlockingQueue.offer("A")); System.out.println(arrayBlockingQueue.offer("B")); System.out.println(arrayBlockingQueue.offer("C"));//true System.out.println("-----------------"); System.out.println(arrayBlockingQueue.peek()); //System.out.println(arrayBlockingQueue.offer("D"));//false does not throw an exception and returns a boolean value System.out.println("-----------------"); System.out.println(arrayBlockingQueue.poll()); System.out.println(arrayBlockingQueue.poll()); System.out.println(arrayBlockingQueue.poll());//It's still first in, first out System.out.println(arrayBlockingQueue.poll());//None does not throw an exception } /** * Wait, block (always block) */ public static void test3() throws InterruptedException { ArrayBlockingQueue arrayBlockingQueue =new ArrayBlockingQueue(3); //Always blocked arrayBlockingQueue.put("A"); arrayBlockingQueue.put("B"); arrayBlockingQueue.put("C"); //arrayBlockingQueue.put("D");// There is no place in the queue. He will wait all the time System.out.println("----------------"); System.out.println(arrayBlockingQueue.take()); System.out.println(arrayBlockingQueue.take()); System.out.println(arrayBlockingQueue.take()); //System.out.println(arrayBlockingQueue.take()); } /** * Wait, (timeout) */ public static void test4() throws InterruptedException { ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(3); arrayBlockingQueue.offer("a"); arrayBlockingQueue.offer("b"); arrayBlockingQueue.offer("c"); //arrayBlockingQueue.offer("d", 2,TimeUnit.SECONDS);// Timeout wait two seconds arrayBlockingQueue.poll(); arrayBlockingQueue.poll(); arrayBlockingQueue.poll(); arrayBlockingQueue.poll(2,TimeUnit.SECONDS); } }
SynchronousQueue synchronization queue
There is no capacity. You must wait for an element to be taken out before you can put another element in it!
package queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; /** * Synchronization queue * Unlike other blockingqueues, synchronous queues do not store elements * put If an element is found, it must be taken out first, otherwise the value cannot be taken out */ public class SynchronousQueueDemo { public static void main(String[] args) { BlockingQueue<String> blockingDeque = new SynchronousQueue<>();//Synchronization queue new Thread(()->{ try { System.out.println(Thread.currentThread().getName() + "PUT 1"); blockingDeque.put("1"); System.out.println(Thread.currentThread().getName() + "PUT 2"); blockingDeque.put("2"); System.out.println(Thread.currentThread().getName() + "PUT 3"); blockingDeque.put("3"); } catch (InterruptedException e) { e.printStackTrace(); } },"T1").start(); new Thread(()->{ try { TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() + "=>" + blockingDeque.take()); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() + "=>" + blockingDeque.take()); TimeUnit.SECONDS.sleep(3); System.out.println(Thread.currentThread().getName() + "=>" +blockingDeque.take()); } catch (InterruptedException e) { e.printStackTrace(); } },"T2").start(); } }
T1PUT 1 T21 T1PUT 2 T22 T1PUT 3 T23
12. Thread pool
Thread pool: 3 methods, 7 parameters and 4 rejection strategies
Pool technology
The operation of the program, essence: occupy the resources of the system! Optimize the use of resources! = = > A technology pool is introduced
Thread pool, connection pool, memory pool, object pool
Pooling Technology: prepare some resources in advance. If someone wants to use them, come to me and give them back to me after use.
Benefits of thread pooling
1. Reduce the trumpet of resources
2. Improve response speed
3. Convenient management
Threads can be reused, the maximum number of concurrent threads can be controlled, and threads can be managed
Three methods of thread pool
Single thread
package pool; import sun.awt.windows.ThemeReader; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //Three methods of Executors tool class //After the thread pool is used, the thread pool is used to create threads public class Test01 { public static void main(String[] args) { ExecutorService threadpool = Executors.newSingleThreadExecutor();//Single thread //Executors.newFixedThreadPool(5);// Create a fixed thread pool size //Executors.newCachedThreadPool();// Scalable cache try{ for(int i =1;i < 10; i++){ //After using thread pool, use thread pool to create threads threadpool.execute(()->{ System.out.println(Thread.currentThread().getName() + "-OK" ); }); } }catch (Exception e){ e.printStackTrace(); }finally { //To stop the thread pool after the program ends threadpool.shutdown(); } } }
pool-1-thread-1-OK pool-1-thread-1-OK pool-1-thread-1-OK pool-1-thread-1-OK pool-1-thread-1-OK pool-1-thread-1-OK pool-1-thread-1-OK pool-1-thread-1-OK pool-1-thread-1-OK Process finished with exit code 0
Create a fixed thread pool size
There are up to five threads executing at the same time
package pool; import sun.awt.windows.ThemeReader; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //Three methods of Executors tool class //After the thread pool is used, the thread pool is used to create threads public class Test01 { public static void main(String[] args) { //ExecutorService threadpool = Executors.newSingleThreadExecutor();// Single thread ExecutorService threadpool = Executors.newFixedThreadPool(5);//Create a fixed thread pool size //Executors.newCachedThreadPool();// Scalable cache try{ for(int i =1;i < 10; i++){ //After using thread pool, use thread pool to create threads threadpool.execute(()->{ System.out.println(Thread.currentThread().getName() + "-OK" ); }); } }catch (Exception e){ e.printStackTrace(); }finally { //To stop the thread pool after the program ends threadpool.shutdown(); } } }
pool-1-thread-1-OK pool-1-thread-4-OK pool-1-thread-3-OK pool-1-thread-2-OK pool-1-thread-4-OK pool-1-thread-3-OK pool-1-thread-5-OK pool-1-thread-1-OK pool-1-thread-2-OK
Cache scalable thread pool
Up to ten threads can execute simultaneously
package pool; import sun.awt.windows.ThemeReader; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //Three methods of Executors tool class //After the thread pool is used, the thread pool is used to create threads public class Test01 { public static void main(String[] args) { //ExecutorService threadpool = Executors.newSingleThreadExecutor();// Single thread //ExecutorService threadpool = Executors.newFixedThreadPool(5);// Create a fixed thread pool size ExecutorService threadpool = Executors.newCachedThreadPool();//Scalable cache try{ for(int i =0;i < 10; i++){ //After using thread pool, use thread pool to create threads threadpool.execute(()->{ System.out.println(Thread.currentThread().getName() + "-OK" ); }); } }catch (Exception e){ e.printStackTrace(); }finally { //To stop the thread pool after the program ends threadpool.shutdown(); } } }
pool-1-thread-1-OK pool-1-thread-4-OK pool-1-thread-7-OK pool-1-thread-5-OK pool-1-thread-2-OK pool-1-thread-6-OK pool-1-thread-8-OK pool-1-thread-9-OK pool-1-thread-10-OK pool-1-thread-3-OK
7 major parameters
Source code analysis
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory)); }
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
The essence is to call ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler); } public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler); } public ThreadPoolExecutor(int corePoolSize,//Core thread pool size int maximumPoolSize,//Maximum thread pool size long keepAliveTime,//The survival time will be released if no one calls it when it times out TimeUnit unit,//Timeout unit BlockingQueue<Runnable> workQueue,//Blocking queue ThreadFactory threadFactory,//To create a thread, generally do not move RejectedExecutionHandler handler) {//Reject policy if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
Manually create a thread pool
package pool; import sun.awt.windows.ThemeReader; import java.util.concurrent.*; //Three methods of Executors tool class //After the thread pool is used, the thread pool is used to create threads public class Test01 { public static void main(String[] args) { //Custom thread pool ExecutorService threadpool = new ThreadPoolExecutor(2, 5, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(3),//Three blocking queues Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());//The bank is full, but someone else comes in, doesn't deal with this person, and throws an exception try{ //The value of the largest bearer queue + the value of max //RejectedExecutionException reject policy, exceeding maximum load for(int i =0;i <6; i++){ //After using thread pool, use thread pool to create threads threadpool.execute(()->{ System.out.println(Thread.currentThread().getName() + "-OK" ); }); } }catch (Exception e){ e.printStackTrace(); }finally { //To stop the thread pool after the program ends threadpool.shutdown(); } } }
/** * Four rejection strategies: * * new ThreadPoolExecutor.AbortPolicy() * When the bank is full, someone else comes in. If you don't deal with this person, throw an exception * * new ThreadPoolExecutor.CallerRunsPolicy() * Where to go! For example, your father asked you to inform your mother to wash clothes, but your mother refused and asked you to go back and inform your father to wash clothes * * new ThreadPoolExecutor.DiscardPolicy() * If the queue is full, lose the task and no exception will be thrown! * * new ThreadPoolExecutor.DiscardOldestPolicy() * When the queue is full, try to compete with the earliest. If the competition fails, no exception will be thrown! */
How is the maximum thread defined
How to set the maximum size of the pool
1.CPU intensive
The CPU of several cores is defined as several cores, which can save the highest performance of the CPU
2.IO intensive
Judge the IO consuming threads in your program,
The program has 15 large tasks, and IO takes up a lot of resources. The IO intensive parameter (maximum number of threads) can be set to greater than 15, which is generally twice as high
13. Four functional interfaces (must be mastered)
Programmers in the new era: lambda expression, chain programming, functional interface, Stream flow computing
Function interface: an interface with only one method
@FunctionalInterface public interface Runnable { public abstract void run(); } //Super multi @ FunctionalInterface //Slow down the programming model and apply it to the bottom layer of the framework in the new version //Foreach (functional interface of consumer type)
Four functional interfaces
Function functional interface
package function; import java.util.function.Function; /** * Function Functional interface * As long as it is a function structure, it can be simplified with lambda */ public class demo01 { public static void main(String[] args) { //Tool class: output input value /*Function function = new Function<String,String>() { @Override public String apply(String o) { return o; } }; System.out.println(function.apply("asd"));*/ Function<String,String> function = (str) ->{return str;}; System.out.println(function.apply("ads")); } }
Predicate type interface
Assertive interface: there is an input parameter, and the return value can only be Boolean!
package function; import java.util.function.Predicate; /* Deterministic interface: there is an input parameter, and the return value can only be boolean value */ public class demo02 { public static void main(String[] args) { //Determine whether the string is empty /* Predicate<String> predicate = new Predicate<String>(){ @Override public boolean test(String s) { return s.isEmpty(); } };*/ Predicate<String> predicate = (str) -> {return str.isEmpty();}; System.out.println(predicate.test(""));//true System.out.println(predicate.test("1"));//false } }
Consumer consumer interface
package function; import java.util.function.Consumer; /* Consumer Consumer interface: only input, no return value */ public class demo03 { public static void main(String[] args) { /*Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } };*/ Consumer<String> consumer = (str) -> { System.out.println(str); }; consumer.accept("asb"); } }
Supplier supply interface
package function; import java.util.function.Supplier; /* supplier Supply type interface, no need to enter, only return value */ public class demo04 { public static void main(String[] args) { /* Supplier supplier = new Supplier<Integer>(){ @Override public Integer get() { System.out.println("get()"); return 1024; } };*/ Supplier<Integer> supplier = () -> {return 1024;}; System.out.println(supplier.get()); } }
14.Stream flow calculation (it is recommended to find some data and deeply understand the method)
What is Stream streaming
Big data: storage + computing
Collection and Mysql are essentially used to store things
All calculations should be left to the flow
package stream; import java.lang.reflect.Array; import java.util.Arrays; import java.util.List; import java.util.Locale; /** * Problem requirements: complete this problem in one minute and can only be solved with one line of code * Now there are five users! Filter: * 1.ID Must be even * 2.Age must be greater than 23 * 3.Change user name to uppercase * 4.User name alphabetical flashback * 5.Output only one user */ public class Test { public static void main(String[] args) { User u1 = new User(1,"a",21); User u2 = new User(2,"b",22); User u3 = new User(3,"c",23); User u4 = new User(4,"d",24); User u5 = new User(6,"e",25); //A collection is storage List<User> users = Arrays.asList(u1, u2, u3, u4, u5); //Calculation of delivery flow //Chain programming users.stream() .filter(u->{return u.getId()%2==0;})//Judge even number .filter(u ->{return u.getAge() >23;})//Judged to be over 23 years old .map(u -> {return u.getName().toUpperCase(Locale.ROOT);})//First name capitalization //. sorted ((uu1, uu2) - > {return uu1. CompareTo (uu2);}) / / positive order .sorted((uu1,uu2)->{return uu2.compareTo(uu1);})//flashback .limit(1) .forEach(System.out::println); } } class User{ private int id; private String name; private int age; public User(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public int getId() { return id; } public String getName() { return name; } public int getAge() { return age; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
15.ForkJoin (it is recommended to find some materials and understand the methods in depth)
Fork/Join framework is basically used_ forkjoin
What is ForkJoin
ForkJoin executes tasks in parallel in JDK 1.7! increase of efficiency. Large amount of data!
Big data: Map Reduce (splitting big tasks into small tasks)
ForkJoin features: job theft
The two terminal queues are maintained in this
ForkJoin
Execute forkjoin through forkjoin pool
Interface
Construction method
Using forkjoin
How to use frokjoin
- 1.forkjoinPool is executed through it
- 2. Calculate the task forkjoinPool.execute(ForkJoinTask task)
- 3. Calculation class should inherit recursivetask (recursive task has return value)
package forkJoin; import java.util.concurrent.RecursiveTask; /** * Task of summation calculation * 3000 6000(frokjoin) 9000(Stream Parallel stream) * How to use frokjoin * 1.forkjoinPool Execute through it * 2.Calculate the task forkjoinPool.execute(ForkJoinTask task) * 3.Calculation class should inherit recursivetask (recursive task has return value) */ public class ForkJoinDemo extends RecursiveTask<Long> { private Long start; private Long end; //critical value private Long temp = 10000L; public ForkJoinDemo(Long start, Long end) { this.start = start; this.end = end; } @Override protected Long compute() { if((end-start) < temp){ Long sum = 0L; for (long i = start ;i<=end;i++){ sum+=i; } return sum; }else { //forkjoin recursion long middle = (start + end) /2; //Intermediate value ForkJoinDemo task1 = new ForkJoinDemo(start,middle); task1.fork();//Split the task and push the task into the thread queue ForkJoinDemo task2 = new ForkJoinDemo(middle,end); task2.fork(); return task1.join() + task2.join(); } } }
package forkJoin; import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.stream.LongStream; public class Test { public static void main(String[] args) { test1();//4391 try { test2(); } catch (ExecutionException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } test3(); } public static void test1(){ Long sum = 0L; long start = System.currentTimeMillis(); for (long i =1L;i<=10_0000_0000;i++){ sum +=i; } long end = System.currentTimeMillis(); System.out.println("sum = " + sum + "Time:" + (end - start)); } public static void test2() throws ExecutionException, InterruptedException { long start = System.currentTimeMillis(); ForkJoinPool forkJoinPool = new ForkJoinPool(); ForkJoinTask<Long> task = new ForkJoinDemo(0L,10_0000_0000L); //Downward transformation ForkJoinTask<Long> submit = forkJoinPool.submit(task);//Submit task Long sum = submit.get();//Obtain results long end = System.currentTimeMillis(); System.out.println("sum=" + sum +"Time:" + (end - start)); } public static void test3(){ long start = System.currentTimeMillis(); //Stream parallel stream Long sum = LongStream.rangeClosed(0L, 10_0000_0000L) .parallel()//Parallel computing .reduce(0,Long::sum);//Call the sum method under Long to output the result long end = System.currentTimeMillis(); System.out.println("sum =" + sum + "Time:" + (end - start)); } }
sum = 500000000500000000 Time: 6183 sum=500065535999828224 Time: 4775 sum =500000000500000000 Time: 154
16. Asynchronous callback
Synchronous callback
Some of our common requests are synchronous callbacks. Synchronous callbacks are blocked. A single thread needs to wait for the result to return before it can continue to execute.
Asynchronous callback
Sometimes, we don't want the program to block on an execution method all the time. We need to execute the subsequent method first, that is, the asynchronous callback here. When we call a method, if the execution time is long, we can pass in a callback method. When the method is executed, let the callee execute the given callback method.
The original intention of Future design: to model the result of an event in the Future
package future; import demo02.C; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; /** * Asynchronous call: completable future * Asynchronous execution * Successful callback * Failed callback */ public class Demo01 { public static void main(String[] args) throws ExecutionException, InterruptedException { /* //Initiate a request //Asynchronous callback an asynchronous callback that has no return value CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{ try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "runAsync=>void"); }); System.out.println("11111"); completableFuture.get();//Get execution results */ //Asynchronous callback with return value //Ajax successful and failed callbacks //The error message is returned CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{ System.out.println(Thread.currentThread().getName() + "supplyAsync=>Integer"); //int i = 10/0; return 1024; }); System.out.println(completableFuture.whenComplete((t,u)->{//Return when successful //When successful, t is 1024 and u is null System.out.println("t=>" + t);//The wrong time is null System.out.println("u=>" + u);//Print java.lang.ArithmeticException: / by zero when an error occurs //java.util.concurrent.CompletionException: //java.lang.ArithmeticException: / by zero }).exceptionally((e)->{//Return on failure System.out.println(e.getMessage()); return 2333; }).get()); /** * sucess code 200 * erroe code 404 500 */ } }
17.JMM
Please talk about your understanding of Volatile
Volatile is a lightweight synchronization mechanism provided by Java virtual machine, which is similar to synchronized but not as powerful.
1. Ensure visibility
2. Atomicity is not guaranteed
3. Prevent instruction rearrangement
What is JMM
JMM: Java Memory Model, nonexistent things, concepts! appointment!
About the synchronization agreement of JMM:
1. Before the thread is unlocked, the shared variables must be immediately flushed back to main memory
2. Before locking the thread, you must read the latest value in the main memory into the working memory!
3. Locking and unlocking are the same lock
Thread: working memory, main memory
Memory partition
java Memory Model JMM understanding and sorting
JMM specifies that memory is mainly divided into main memory and working memory. The main memory and working memory here are divided with the JVM memory (heap, stack and method area) at different levels. If it is necessary to correspond, the main memory corresponds to the object instance in the Java heap, and the working memory corresponds to some areas in the stack. At the bottom, the main memory corresponds to the physical memory of the hardware, Working memory corresponds to registers and caches.
In the design of the JVM, it is considered that if the JAVA thread directly operates the main memory every time it reads and writes variables, it will have a great impact on the performance, so each thread has its own working memory. The variables in the working memory are a copy of the main memory. The threads read and write variables directly in the working memory, rather than directly operating the variables in the main memory. However, there will be a problem. When a thread modifies a variable in its working memory, it is invisible to other threads, which will lead to thread insecurity. Because JMM has formulated a set of standards to ensure that developers can control when memory will be synchronized to other threads when writing multithreaded programs.
8 operations
There are 8 kinds of memory interactive operations. The virtual machine implementation must ensure that each operation is atomic and cannot be separated (for variables of double and long types, exceptions are allowed for load, store, read and write operations on some platforms)
-
lock: a variable that acts on main memory and identifies a variable as thread exclusive
-
unlock: a variable that acts on the main memory. It releases a locked variable, and the released variable can be locked by other threads
-
read: acts on the main memory variable. It transfers the value of a variable from the main memory to the working memory of the thread for subsequent load actions
-
load: a variable that acts on working memory. It puts the read operation from main memory into working memory
-
Use: acts on variables in working memory. It transfers variables in working memory to the execution engine. Whenever the virtual machine encounters a value that needs to be used, it will use this instruction
-
assign: acts on a variable in working memory. It puts a value received from the execution engine into the variable copy in working memory
-
store: a variable that acts on main memory. It transfers the value of a variable from working memory to main memory for subsequent write
-
write: acts on a variable in main memory. It puts the value of the variable obtained from the working memory by the store operation into the variable in main memory
JMM formulates the following rules for the use of these eight instructions:
-
One of read and load, store and write operations is not allowed to appear alone. That is, read must be loaded and store must be written
-
The thread is not allowed to discard its latest assign operation, that is, after the data of the work variable has changed, it must inform the main memory
-
A thread is not allowed to synchronize data without assign from working memory back to main memory
-
A new variable must be born in main memory. Working memory is not allowed to directly use an uninitialized variable. This means that the assign and load operations must be performed before the use and store operations are performed on the linked variables
-
Only one thread can lock a variable at a time. After multiple locks, you must perform the same number of unlocks to unlock
-
If you lock a variable, the value of this variable in all working memory will be cleared. Before the execution engine uses this variable, you must re load or assign to initialize the value of the variable
-
If a variable is not locked, it cannot be unlocked. You cannot unlock a variable that is locked by another thread
-
Before unlock ing a variable, you must synchronize the variable back to main memory
JMM is responsible for these eight operation rules and Some special rules of volatile You can determine which operations are thread safe and which operations are thread unsafe. However, these rules are so complex that it is difficult to analyze them directly in practice. Therefore, generally, we will not analyze through the above rules. More often, use java's happen before rule for analysis.
Problem: the program does not know that the value of main memory has been modified
package volatileT; import java.util.concurrent.TimeUnit; public class JMMDemo { private static int num = 0; public static void main(String[] args) { new Thread(()->{//Thread 1 while(num == 0){ } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } num = 1; System.out.println(num); } }
18.Volatile
1. Ensure visibility
package volatileT; import java.util.concurrent.TimeUnit; public class JMMDemo { //Without volatile, the program will loop! //Adding volatile ensures visibility private volatile static int num = 0; public static void main(String[] args) { new Thread(()->{//Thread 1 is not aware of changes in main memory while(num == 0){ } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } num = 1; System.out.println(num); } }
2. Atomicity is not guaranteed
Atomicity: indivisible
Thread A cannot be disturbed or divided when executing tasks. Either succeed or fail at the same time
package volatileT; //Atomicity is not guaranteed public class VDemo02 { private volatile static int num = 0; /*public synchronized static void add(){ num++; }//200000*/ public static void add(){ num++; } //Theoretically, the num result is 2w public static void main(String[] args) { for (int i =1;i<=20;i++){ new Thread(()->{ for (int j=0;j<1000;j++){ add(); } }).start(); } while(Thread.activeCount()>2){ //There are two threads in java that execute by default, one is main and the other is GC Thread.yield(); } System.out.println(Thread.currentThread().getName() + " " + num); } }
How to ensure atomicity without lock and synchronized
Use atomic classes to solve atomicity problems
package volatileT; import java.util.concurrent.atomic.AtomicInteger; //Atomicity is not guaranteed public class VDemo02 { //Integer of atomic class private volatile static AtomicInteger num = new AtomicInteger(); /*public synchronized static void add(){ num++; }//200000*/ public static void add(){ //num++;// Not an atomic operation num.getAndIncrement();//+1. Underlying CAS for method } //Theoretically, the num result is 2w public static void main(String[] args) { for (int i =1;i<=20;i++){ new Thread(()->{ for (int j=0;j<1000;j++){ add(); } }).start(); } while(Thread.activeCount()>2){ //There are two threads in java that execute by default, one is main and the other is GC Thread.yield(); } System.out.println(Thread.currentThread().getName() + " " + num); } }
The bottom of these classes are directly linked to the operating system! Modify the value in memory! Unsafe class is a very special existence!
3. Command rearrangement is prohibited
Instruction rearrangement
What is instruction rearrangement?: The computer does not execute the program we write as you write.
Source code - > compiler optimized rearrangement - > instruction parallelism may also rearrange - > memory system may also rearrange - > execution
When the processor performs instruction rearrangement, it will consider the dependency between data
int x = 1; // 1 int y = 2; // 2 x = x + 5; // 3 y = x * x; // 4
What we expect: 1234 may become 2134 or 1324 when executed, but it can't be 4123!
Premise: the four values of a, B, x, y are all 0 by default:
May cause impact and get different results:
Thread A | Thread B |
---|---|
x = a | y = b |
b =1 | a = 2 |
Normal results: x = 0, y = 0;
However, since the specified rearrangement may change the execution order, the following results occur:
Thread A | Thread B |
---|---|
b = 1 | a = 2 |
x = a | y = b |
Abnormal result caused by instruction rearrangement: x = 2, y= 1;
volatile avoids instruction rearrangement:
The memory barrier is a CPU instruction. effect:
1. Keep the execution sequence of specific operations!
2. Memory visibility of some variables can be guaranteed (visibility is realized by volatile)
Volatile can maintain visibility and cannot guarantee atomicity. Due to the memory barrier, it can avoid instruction rearrangement!
volatile memory barrier is used most in singleton mode!
19. Singleton mode
Singleton pattern of JAVA design pattern
Hungry man style DCL lazy man style, deep study
What is singleton mode
Singleton pattern is a common design pattern in java. There are several ways to write singleton patterns. Here we mainly introduce three kinds: lazy singleton and hungry singleton
The singleton pattern ensures that a class has only one instance, and instantiates itself and provides this instance to the whole system. In the computer system, the driver objects of thread pool, cache, log object, dialog box, printer and graphics card are often designed as singletons. These applications have more or less the function of resource manager. Each computer can have several printers, but only one Printer Spooler to avoid two print jobs being output to the printer at the same time.
The singleton mode has the following characteristics:
1. A singleton class can only have one instance.
2. A singleton class must create its own unique instance.
3. The singleton class must provide this instance to all other objects.
Hungry Han style
//Hungry Chinese singleton class. It has been instantiated by itself during class initialization public class Singleton1 { private Singleton1() {} private static final Singleton1 single = new Singleton1(); //Static factory method public static Singleton1 getInstance() { return single; } }
Hungry Chinese style has created a static object for the system to use at the same time as the class is created, which will not change in the future, so it is inherently thread safe.
package single; //Hungry Han style single case public class Hungry { //It may waste space //Load all the objects private byte[] date1 = new byte[1024*1024]; private byte[] date2 = new byte[1024*1024]; private byte[] date3 = new byte[1024*1024]; private byte[] date4 = new byte[1024*1024]; private Hungry(){ } //When the class is created, a static object has been created for use private final static Hungry HUNGRY = new Hungry(); public static Hungry getInstance(){ return HUNGRY; } }
Lazy style
//Lazy singleton class. Instantiate yourself on the first call public class Singleton { private Singleton() {} private static Singleton single=null; //Static factory method public static Singleton getInstance() { if (single == null) { single = new Singleton(); } return single; } }
package single; //Lazy singleton mode public class LazyMan { public LazyMan() { System.out.println(Thread.currentThread().getName() + "ok" ); } private volatile static LazyMan lazyMan;//lazyMan must be added volatile to prevent instruction rearrangement public static LazyMan getInstance(){ //Lock //Double detection lock mode if (lazyMan == null){ synchronized (LazyMan.class){//Only when it's empty do you start to grab the lock if (lazyMan == null) { lazyMan = new LazyMan();//Not an atomic operation /** * 1.Allocate memory space * 2.Execute the construction method to initialize the object * 3.Point this object to this space * * The expected order is: 123 * Actual execution under special circumstances: 132 = = = > thread A has no problem at this time * If an additional B thread is added * At this time, lazyMan has not completed the construction */ } } } return lazyMan; } //Single thread is OK //Multithreading concurrency //Thread startup occasionally succeeds and occasionally fails public static void main(String[] args) { for (int i =0;i<10;i++){ new Thread(()->{ LazyMan.getInstance(); }).start(); } } }
LazyMan avoids external instantiation of classes by limiting the construction method to private. Within the scope of the same virtual machine, the only instance of LazyMan can only be accessed through the getInstance() method.
However, the above lazy singleton implementation does not consider thread safety. It is thread unsafe. Multiple LazyMan instances are likely to occur in a concurrent environment. To achieve thread safety, the getInstance method needs to be modified. The above method uses double check locking, and the following method uses static inner classes
It not only realizes thread safety, but also avoids the performance impact caused by synchronization.
public class Singleton { private static class LazyHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return LazyHolder.INSTANCE; } }
Reflection to destroy singleton mode
package single; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; //Lazy singleton mode public class LazyMan { private static boolean flag = false;//Flag bit //The solution, but not completely public LazyMan() { synchronized (LazyMan.class){ if (flag == false){ flag = true; }else { throw new RuntimeException("Do not attempt to construct exceptions using reflection"); } } System.out.println(Thread.currentThread().getName() + "ok" ); } private volatile static LazyMan lazyMan;//lazyMan must be added volatile to prevent instruction rearrangement public static LazyMan getInstance(){ //Lock //Double detection lock mode if (lazyMan == null){ synchronized (LazyMan.class){//Only when it's empty do you start to grab the lock if (lazyMan == null) { lazyMan = new LazyMan();//Not an atomic operation /** * 1.Allocate memory space * 2.Execute the construction method to initialize the object * 3.Point this object to this space * * The expected order is: 123 * Actual execution under special circumstances: 132 = = = > thread A has no problem at this time * If an additional B thread is added * At this time, lazyMan has not completed the construction */ } } } return lazyMan; } //Single thread is OK //Multithreading concurrency //Thread startup occasionally succeeds and occasionally fails public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { //Reflection destroys the constructor //LazyMan instance = LazyMan.getInstance(); Field flag = LazyMan.class.getDeclaredField("flag"); flag.setAccessible(true); Constructor<LazyMan> declaredConstructors = LazyMan.class.getDeclaredConstructor(null); declaredConstructors.setAccessible(true); LazyMan instance = declaredConstructors.newInstance(); flag.set(instance,false); LazyMan instance2 = declaredConstructors.newInstance(); System.out.println(instance); System.out.println(instance2); } }
Solution
public LazyMan() { synchronized (LazyMan.class){ if (flag == false){ flag = true; }else { throw new RuntimeException("Do not attempt to construct exceptions using reflection"); } } }
Use enumeration to resolve reflection corruption
package single; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; //What is enum? //Itself can be a class class public enum Enumsingle { INSTANCE; public Enumsingle getInstance(){ return INSTANCE; } } class Test{ public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Enumsingle instance = Enumsingle.INSTANCE; Constructor<Enumsingle> declaredConstructor = Enumsingle.class.getDeclaredConstructor(String.class,int.class); declaredConstructor.setAccessible(true); Enumsingle instance2 = declaredConstructor.newInstance(); //Nosuchmethodexception: single. Enumsingle. < init > () no null parameter constructor //IllegalArgumentException: Cannot reflectively create enum objects. Reflection corruption is not allowed System.out.println(instance); System.out.println(instance2); } }
20. In depth understanding of CAS
What is CAS
Big factory, you must study the bottom! Breakthrough! Internal skill cultivation, operating system, computer network principle
package cas; import java.util.concurrent.atomic.AtomicInteger; public class CASDemo { //Compare and exchange public static void main(String[] args) { AtomicInteger atomicInteger = new AtomicInteger(2020);//Atomic class /* Expected update public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } */ //If it is the same as the expected value, it will be updated. CAS is the concurrency primitive of CPU System.out.println(atomicInteger.compareAndSet(2020, 2021)); System.out.println(atomicInteger.get()); // 2021 System.out.println(atomicInteger.compareAndSet(2020, 20201)); System.out.println(atomicInteger.get());//2021 } }
unsafe class
CAS: compare the value in the current working memory with the value in the main memory. If this value is expected, execute the operation! If not, keep cycling!
Disadvantages:
1. The cycle will take time
2. The atomicity of only one shared variable can be guaranteed at one time
3. ABA problem
CAS: ABA problem (civet cat for Prince)
package cas; import java.util.concurrent.atomic.AtomicInteger; public class CASDemo { //Compare and exchange public static void main(String[] args) { AtomicInteger atomicInteger = new AtomicInteger(2020);//Atomic class /* Expected update public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } */ //We write the usual sql: optimistic lock //If it is the same as the expected value, it will be updated. CAS is the concurrency primitive of CPU //*******Troublemaker thread********** System.out.println(atomicInteger.compareAndSet(2020, 2021)); System.out.println(atomicInteger.get()); // 2021 System.out.println(atomicInteger.compareAndSet(2021, 2020)); System.out.println(atomicInteger.get()); // 2021 //********Expected thread********* System.out.println(atomicInteger.compareAndSet(2020, 2021)); System.out.println(atomicInteger.get());//2021 } }
How to solve this problem? Atomic reference
21. Atomic reference
Atomic operation with version number
package cas; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicStampedReference; public class CASDemo { //Compare and exchange public static void main(String[] args) { //AtomicInteger atomicInteger = new AtomicInteger(2020);// Atomic class //Integer uses the object caching mechanism. The default range is - 128 ~ 127. It is recommended to use the static factory method valueOf to obtain object instances instead of new, because valueOf uses caching, and new will create new objects and allocate new memory space; AtomicStampedReference<Integer> atomicInteger = new AtomicStampedReference<>(2020,1);//Initial value, version number, timestamp new Thread(()->{ int stamp = atomicInteger.getStamp();//Get version number System.out.println("A = >" + stamp); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } //For the last two parameters, get the latest version number and add the version number + 1 System.out.println(atomicInteger.compareAndSet(2020, 2022, atomicInteger.getStamp(), atomicInteger.getStamp() + 1)); System.out.println("A2 = >"+atomicInteger.getStamp()); //Take this value back System.out.println(atomicInteger.compareAndSet(2022, 2020, atomicInteger.getStamp(), atomicInteger.getStamp() + 1)); System.out.println("A3 = >"+atomicInteger.getStamp()); },"a").start(); new Thread(()->{ int stamp = atomicInteger.getStamp();//Get version number System.out.println("B = >" + stamp); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(atomicInteger.compareAndSet(2020, 6666, stamp, stamp + 1)); System.out.println("b2 = >" +atomicInteger.getStamp()); },"b").start(); } }
**Note: Integer uses the object cache mechanism. The default range is - 128 ~ 127. It is recommended to use the static factory method valueOf to obtain object instances instead of new, because valueOf uses cache, and new will create new objects and allocate new memory space** Every 2020 is a new value
After modification
package cas; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicStampedReference; public class CASDemo { //Compare and exchange public static void main(String[] args) { //AtomicInteger atomicInteger = new AtomicInteger(2020);// Atomic class //Integer uses the object caching mechanism. The default range is - 128 ~ 127. It is recommended to use the static factory method valueOf to obtain object instances instead of new, because valueOf uses caching, and new will create new objects and allocate new memory space; AtomicStampedReference<Integer> atomicInteger = new AtomicStampedReference<>(11,1);//Initial value, version number, timestamp new Thread(()->{ int stamp = atomicInteger.getStamp();//Get version number System.out.println("A = >" + stamp); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } //For the last two parameters, get the latest version number and add the version number + 1 System.out.println(atomicInteger.compareAndSet(11, 22, atomicInteger.getStamp(), atomicInteger.getStamp() + 1)); System.out.println("A2 = >"+atomicInteger.getStamp()); //Take this value back System.out.println(atomicInteger.compareAndSet(22, 11, atomicInteger.getStamp(), atomicInteger.getStamp() + 1)); System.out.println("A3 = >"+atomicInteger.getStamp()); },"a").start(); new Thread(()->{ int stamp = atomicInteger.getStamp();//Get version number System.out.println("B = >" + stamp); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(atomicInteger.compareAndSet(11, 66, stamp, stamp + 1)); System.out.println("b2 = >" +atomicInteger.getStamp()); },"b").start(); } }
22. Understanding of various locks
1. Fair lock and unfair lock
Fair lock: very fair. You can't jump the queue. You must come first!
Unfair lock: very unfair. You can jump in the queue (all unfair by default)
public ReentrantLock() { sync = new NonfairSync(); } public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
2. Re entrant lock
Recursive lock
Synchroized
package lock; //Synchorized public class Demo01 { public static void main(String[] args) { Phone phone = new Phone(); new Thread(()->{ phone.sms(); },"a").start(); new Thread(()->{ phone.sms(); },"b").start(); } } class Phone{ public synchronized void sms(){ System.out.println(Thread.currentThread().getName() + "sms"); call(); There are locks here, too(sms Inside the lock call lock) } public synchronized void call(){ System.out.println(Thread.currentThread().getName() + "call"); } }
Lock lock
package lock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Demo02 { public static void main(String[] args) { Phone2 phone = new Phone2(); new Thread(()->{ phone.sms(); },"a").start(); new Thread(()->{ phone.sms(); },"b").start(); } } class Phone2{ Lock lock = new ReentrantLock(); public void sms(){ lock.lock();//Details first lock //lock locks must be paired, or they will die inside try { System.out.println(Thread.currentThread().getName() + "sms"); call(); There are locks here, too(sms Inside the lock call lock) } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public synchronized void call(){ lock.lock();//Second lock try { System.out.println(Thread.currentThread().getName() + "call"); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } }
3. Spin lock
spinlock
package lock; import javax.swing.text.rtf.RTFEditorKit; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; public class TestSpinlock { public static void main(String[] args) { /*ReentrantLock reentrantLock = new ReentrantLock(); reentrantLock.lock(); reentrantLock.unlock();*/ //The bottom layer is implemented by spin lock CAS SpinlockDemo spinlockDemo = new SpinlockDemo(); new Thread(()->{ spinlockDemo.mylock(); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }finally { spinlockDemo.myunlock(); } },"T1").start(); //T1 gets the lock and T2 keeps spinning. After T1 is unlocked, T2 obtains the lock end spin new Thread(()->{ spinlockDemo.mylock(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }finally { spinlockDemo.myunlock(); } },"T2").start(); } }
4. Deadlock
What is a deadlock?
Deadlock test, how to eliminate Deadlock:
package lock; import single.LazyMan; import java.util.concurrent.TimeUnit; public class DeadlockDemo { public static void main(String[] args) { String lockA = "lockA"; String lockB = "lockB"; new Thread(new MyThread(lockA,lockB),"T1").start(); new Thread(new MyThread(lockB,lockA),"T2").start(); } } class MyThread implements Runnable{ private String lockA; private String lockB; public MyThread(String lockA, String lockB) { this.lockA = lockA; this.lockB = lockB; } @Override public void run() { synchronized (lockA){ //lockA wants B System.out.println(Thread.currentThread().getName() + "lock"+ lockA + "=> get" + lockB); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lockB){ //B wants A System.out.println(Thread.currentThread().getName() + "lock" + lockB + "=> get" + lockA); } } } }
solve the problem
1. Use JPS to locate the process number jps-l
2. Use jstack to view process information and process number to find deadlock information
Interview, work! Troubleshooting:
1. Log
2. Stack information