Crazy God said | JUC Concurrent Programming Notes + their own understanding and sorting

Keywords: Java Multithreading thread JUC

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

modeThrow exceptionIf there is a return value, no exception will be thrownBlocking waitTimeout wait
add toaddoffer()put()offer(,)
removeremovepoll()take()poll(,)
Inspection team head elementelementpeek()--

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 AThread B
x = ay = b
b =1a = 2

Normal results: x = 0, y = 0;

However, since the specified rearrangement may change the execution order, the following results occur:

Thread AThread B
b = 1a = 2
x = ay = 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

Posted by hoffmeister on Tue, 12 Oct 2021 12:18:28 -0700