JUC concurrent programming

Posted by daniminas on Sun, 23 Jan 2022 13:25:22 +0100

JUC (concurrent programming)

1. What is JUC

java.util.concurrent package is a tool class used in concurrent programming. It has the following three packages:

java.util Toolkit

Business: common Thread code Thread

Runnable has no return value and its efficiency is relatively lower than that of Callable!)

(

2. Threads and processes

Threads and processes

Process: a program, QQ exe,music.exe, a collection of programs

A process often contains multiple threads, including at least one

Java has two threads by default? 2 main threads, GC threads

Thread: open a process Typora, write, and save automatically (thread is responsible for)

For java: Thread, Runnable, Callable

Can Java really start threads? I can't drive!

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 */
            }
        }
    }

    private native void start0();   // Local methods, call the underlying c + +, java can not directly operate the hardware!

Concurrency and parallelism

Concurrent programming: concurrency and parallelism

Concurrency (multiple threads operate on the same resource)

  • With one CPU core, multiple threads can be simulated. The world's martial arts can only be broken quickly! Fast alternation

Parallel (multiple people walking together)

  • The CPU is multi-core, and multiple threads execute together; Use thread pool)

Code view cpu cores

package com.kuang.juc.demo01;

public class Test {

    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

Several states of threads

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,   // newborn

        /**
         * 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.
         */
        RUNNABLE,  // function

        /**
         * 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}.
         */
        BLOCKED,  // block

        /**
         * 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.
         */
        WAITING,  // Wait (dead, etc.), block

        /**
         * 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>
         */
        TIMED_WAITING,  // Timeout waiting

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;  // termination
    }

wait/sleep difference

1. From different classes

wait => Object

sleep => Thread

2. About lock release

wait will release the lock. Sleep will sleep with the lock. It won't release!

3. The scope of use is different

wait must be used in synchronous code blocks

Sleep can sleep anywhere and can be used anywhere

4. Need to catch exceptions

wait also needs to catch exceptions

sleep must catch exceptions

3. Lock lock

Traditional synchonized

package com.kuang.juc.demo01;


// Basic ticket example

/**
 * Real multi-threaded development, reduce coupling!
 * Thread is a separate resource class without any affiliated operations!
 *  1.Properties and methods
 */
public class SaleTicketDemo01 {

    public static void main(String[] args) {
        // Concurrency: multiple threads operate on the same resource class. Just throw the resource class into the thread!
        Ticket ticket = new Ticket();

        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, methods
    private int nums = 30;

    // How to sell tickets
    // synchronized essence: queue + lock
    public synchronized void sale(){
       if (nums>0){
           System.out.println(Thread.currentThread().getName()+"Sold"+nums--+"Tickets. Remaining: "+nums+"Ticket");
       }
    }

}

result:

)

summary

After adding the synchonized keyword, it becomes a synchronization method (queue locking). It's equivalent to you going to the school canteen to buy rice. The window to buy rice is lined up one by one. After the people in the row went to give the bowl to their aunt, it's equivalent to adding a lock to themselves. After the aunt finished the meal, she gave the bowl to you, which is equivalent to releasing the lock. After the release, the people behind can line up to buy food again.

Lock interface

)

)

)

Fair lock: very fair. There is a first come first served order 3h 3s

Unfair lock: very unfair. You can jump the queue (default)

lock to buy tickets

package com.kuang.juc.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. Just throw the resource class into the thread!
        Ticket2 ticket = new Ticket2();

        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();

    }

}


// lock
class Ticket2{
    // Properties, methods
    private int nums = 30;

    Lock lock = new ReentrantLock();

    public void sale(){
        lock.lock();  //Lock


        try {
            // Business code
            if (nums>0){
                System.out.println(Thread.currentThread().getName()+"Sold"+nums--+"Tickets. Remaining: "+nums+"Ticket");
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock(); //Unlock
        }

    }

}

The difference between synchronized and Lock

  1. Synchoizned is a built-in keyword; Lock is a java class
  2. Synchonized cannot judge the state of obtaining the lock; Lock can determine whether a lock has been obtained
  3. Synchronized will automatically release the lock; Lock, you must release the lock manually! If the lock * * is not released, it will deadlock**
  4. Synchronized thread 1 (lock acquisition, blocking), thread 2 (wait, silly, etc.); Lock doesn't have to wait!
  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; Lock is suitable for locking a large number of synchronization codes!

What is a lock? How to judge who is locked?

4. Producer consumer issues

Interview: Singleton mode, sorting algorithm, producer consumer problem, deadlock

Synchonized version of producer consumer issues

package com.kuang.juc.pc;

/**
 * Communication problems between threads: producer and consumer problems! Wait for wake-up, notify wake-up
 * Threads alternately perform a and B operations, and the same variable num = 0
 * A  num+1
 * B  num-1
 */
public class A {

    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.increment();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.decrement();
            }
        },"B").start();
    }

}

// Pithy formula: judge, wait, business, notice!
class Data{ // Digital resources

    private int num = 0;

    //+1
    public synchronized void increment(){
        if (num != 0){ // 0
            // wait for
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        num++;
        System.out.println(Thread.currentThread().getName()+"==>"+num);
        // Notify other threads that I + 1 is over
        this.notifyAll();
    }

    //-1
    public synchronized void decrement(){
        if (num == 0){  //1
           // wait for
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        num--;
        System.out.println(Thread.currentThread().getName()+"==>"+num);
        // Notify other threads that I -1'm done
        this.notifyAll();
    }

}

The problem exists. There are 4 threads a, B, C and D

)

There was a problem and 2 and 3 were found

solve

)

Judge the original if = = > while to prevent false wake-up!

Note: if can only be judged once (if is not judged after the second thread enters, it is directly + 1, and 2 occurs, which is unsafe!), When using while, you will judge every time you enter this method, which is very safe!

Producer consumer issues of JUC version

)

Find the Condition through lock

)

code implementation

package com.kuang.juc.pc;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Communication problems between threads: producer and consumer problems! Wait for wake-up, notify wake-up
 * Threads alternately perform a and B operations, and the same variable num = 0
 * A  num+1
 * B  num-1
 */
public class B {

    public static void main(String[] args) {
        Data2 data = new Data2();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();

    }
}

class Data2{ // Digital resource class

    private int num = 0;

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

//condition.await(); // wait for
//condition.signalAll(); // awaken

    //+1
    public void increment() throws InterruptedException {
        lock.lock();  //Lock
        try {
            // Business code
            while (num != 0){ // 0
                // wait for
                condition.await();
            }
            num++;
            System.out.println(Thread.currentThread().getName()+"==>"+num);
            // Notify other threads that I + 1 is over!
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock(); //Unlock
        }
    }

    //-1
    public void decrement() throws InterruptedException {
        lock.lock(); // Lock
        try {
            // Business code
            while (num == 0){  //1
               condition.await();
            }
            num--;
            System.out.println(Thread.currentThread().getName()+"==>"+num);
            // Notify other threads that I -1'm done!
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock(); //Unlock
        }
    }

}

result:

)

Question: if you want A to finish B, C and D

Any new technology is definitely not only covering the original technology, but also has its own advantages and supplements!

Condition precise notification and wake-up thread

Code implementation:

package com.kuang.juc.pc;


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A  B  C  3 Sequential execution of threads
 * A-->B-->C-->A......
 */
public class C {

    public static void main(String[] args) {
        Data3 data = new Data3();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.printA();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.printB();
            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.printC();
            }
        },"C").start();
    }

}

class Data3 {  // Resource class

    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();  //Synchronization monitor
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private int flag = 1;  // 1A   2B   3C

    public void printA() {
        lock.lock();
        try {
            // Business code, judgment, waiting, execution, notification, Trilogy
            while (flag != 1) {
                //wait for
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>AAAAAAAAAA");
            // Wake up, wake up the designated person, B
            flag = 2;
            condition2.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void printB() {
        lock.lock();
        try {
            while (flag != 2) {
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>BBBBBBBBBB");
            // Wake up, wake up the designated person, C
            flag = 3;
            condition3.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printC() {
        lock.lock();
        try {
            while (flag != 3) {
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>CCCCCCCCCC");
            // Wake up, wake up the designated person, A
            flag = 1;
            condition1.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

View results:

5. 8 lock phenomenon

How to judge who the lock is? Always know what a lock is and who it is?

Object, class

Deep understanding of our locks

5.1 test I

package com.kuang.juc.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 8 Lock is about 8 questions about lock
 * 1,Under standard conditions, do two threads print, call or send text messages first? 1 / send text messages 2 / make phone calls
 * 2,Sending SMS is delayed for 4s. Do the two threads print, call or send SMS first? 1 / send text messages 2 / make phone calls
   Cause: only one lock of the caller was obtained!
 */
public class Test1 {

    public static void main(String[] args) {
        Phone phone = new Phone();

        // Existence of lock
        new Thread(()->{
            phone.sendSms();
        },"A").start();

        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 method caller!
    // The two methods use the same lock. Whoever gets it first will execute it!

    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("send message");
    }

    public synchronized void call(){
        System.out.println("phone");
    }

}

5.2 test II

package com.kuang.juc.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 3,After adding a common method, print and send text messages first or hello? 1 / Hello 2 / common method of sending SMS
 * 4,Two objects, two synchronization methods, print and send text messages or print and call first? 1 / call 2 / text
 *
 */
public class Test2 {

    public static void main(String[] args) {
        // Two objects, two callers, two locks!
        Phone2 phone1 = new Phone2();
        Phone2 phone2 = new Phone2();

        // Existence of lock
        new Thread(()->{
            phone1.sendSms();
        },"A").start();

        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 method caller!
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("send message");
    }

    public synchronized void call(){
        System.out.println("phone");
    }

    // There's no lock here! It is not a synchronization method and is not affected by the lock!
    public void hello(){
        System.out.println("hello");
    }

}

5.3 test III

package com.kuang.juc.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 5,Add two static synchronization methods. There is only one object. Print and send text messages or call first? 1 / send text messages 2 / call because the lock is class, and there is only one class template, one lock!
 * 6,Two objects, two static synchronization methods, print, send text messages or call first? 1 / send text messages 2 / call because the lock is class, and there is only one class template, one lock!
 *
 */
public class Test3 {

    public static void main(String[] args) {

        // There is only one class template for the two objects, static, and the lock is class
        Phone3 phone1 = new Phone3();
        Phone3 phone2 = new Phone3();

        // Existence of lock
        new Thread(()->{
            phone1.sendSms();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            phone2.call();
        },"B").start();
    }

}

// Phone3 has only one class object
class Phone3{

    // The object of the synchronized lock is the method caller!
    // Static static methods are available as soon as the Class is loaded! The lock is Class
    // Lock Class template!
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("send message");
    }

    public static synchronized void call(){
        System.out.println("phone");
    }

    // There's no lock here! It is not a synchronization method and is not affected by the lock!
    public void hello(){
        System.out.println("hello");
    }

}

5.4 test IV

package com.kuang.juc.lock8;

import java.util.concurrent.TimeUnit;


/**
 * 1,1 A static synchronization method, a common synchronization method, an object, print, send text messages or call first? 1 / call 2 / text
 *   Cause of 1: call to call a lock, and the lock is the caller; Call another lock for texting. The class template of the lock is class!
 * 2,1 Two static synchronization methods, one common synchronization method and two objects. Print and send text messages or call first? 1 / call 2 / text
 *   Cause of 2: call to call a lock, and the lock is the caller phone2; Call another lock for texting. The class template of the lock is class!
 */
public class Test4 {

    public static void main(String[] args) {

        // The lock obtained is the class template class
        Phone4 phone1 = new Phone4();

        // The lock obtained is caller phone2
        Phone4 phone2 = new Phone4();

        // Existence of lock
        new Thread(()->{
            phone1.sendSms();
        },"A").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            phone2.call();
        },"B").start();
    }

}


class Phone4{

    // The static synchronization method locks the class class template
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("send message");
    }

    // Common synchronization methods lock the caller
    public synchronized void call(){
        System.out.println("phone");
    }

}

summary

In the above example, it is found that:

  • New = > the lock is a specific mobile phone of this
  • Static = > the lock is the only template of class

synchronized is the basis of synchronization: every object in java can be used as a lock!

The specific manifestations are as follows:

  • For normal synchronization methods, the lock is the current instance object (this)
  • For static synchronization methods, the lock is the current Class object
  • For synchronous method blocks, locks are configuration objects in synchronized parentheses

6. Collection class unsafe

List is not safe

package com.kuang.juc.unsafe;


import java.lang.reflect.Array;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;


// java. util. Concurrent modificationexception concurrent modification exception!
public class ListTest {

    public static void main(String[] args) {
        // Is it unsafe to send an ArrayList? synchonized;
        /**
         * Solution:
         *  1, List<String> list = new Vector<>();
         *  2, List<String> list = Collections.synchronizedList(new ArrayList<>());
         *  3, List<String> list = new CopyOnWriteArrayList<>();
         */
        // CopyOnWrite is an optimization strategy in the field of copy COW computer programming when writing!
        // When multiple threads call, list, read, fixed, write (there may be overwrite)
        // Avoid data problems caused by overwriting when writing!

        // CopyOnWriteArrayList is better than Vector. Where is it?
        // Vector (synchonized is used in the add method, which is inefficient) 
        // CopyOnWriteArrayList (the add method uses lock lock, which is more efficient than vector)

        List<String> list = new CopyOnWriteArrayList<>();
        for (int i = 1; i <= 10; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(list);
            },String.valueOf(i)).start();
        }

    }

}

To view the add method of CopyOnWriteArrayList:

[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-a5aauini-1625379008053)()]

Learning methods: 1. Be able to use it first. 2. Compare goods and find other solutions. 3. Analyze the source code

Set is not safe

package com.kuang.juc.unsafe;

import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;

// java. util. Concurrent modificationexception concurrent modification exception
public class TestSet {

    public static void main(String[] args) {
        /**
         * Solution:
         *  1,Set<String> set = Collections.synchronizedSet(new HashSet<>());  Convert to synchonized by tool class
         *  2,Set<String> set = new CopyOnWriteArraySet<>();  Copy on write for performance and security!
         */
        Set<String> set = new CopyOnWriteArraySet<>();
        
        for (int i = 1; i <= 30; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(set);
            }).start();
        }

    }

}

What is the bottom layer of HashSet?

public HashSet() {
    map = new HashMap<>();
}

// add.   The essence of ashset is the key of map, because the key cannot be repeated!
public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

// PRESENT.  Constant value!
private static final Object PRESENT = new Object();

Map is not secure

Review the basic operation of map

[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-cepap1zo-1625379008055)()]

package com.kuang.juc.unsafe;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

// java. util. Concurrent modificationexception concurrent modification exception!
public class MapTest {

    public static void main(String[] args) {
        // Is map used like this? No, HashMap is not used in multithreading
        // What is the default equivalent?
        // Load factor, initialization capacity

        /**
         * resolvent:
         *  1, Map<String, String> map = Collections.synchronizedMap(new HashMap<>());  The tool class is replaced by a safe map collection
         *  2,  Map<String, String> map = new ConcurrentHashMap<>();
         **/
        Map<String, String> map = new ConcurrentHashMap<>();

        for (int i = 1; i <= 30 ; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
                System.out.println(map);
            },String.valueOf(i)).start();
        }

    }

}

7. Walk into Callable

1. Can have return value

2. Exceptions can be thrown

3. The methods are different, run() / call()

package com.kuang.juc.callable;

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 Runnable()).start();
        //  new Thread(new FutureTask<V>()).start();
        //  new Thread(new FutureTask<V>( Callable() )).start();

        new Thread().start();  //How do I start Callable

        MyThread myThread = new MyThread();  // Callable interface is implemented
        FutureTask futureTask = new FutureTask<>(myThread);    // Adaptation class

        new Thread(futureTask,"A").start();
        new Thread(futureTask,"B").start();  // With cache

        Integer o = (Integer) futureTask.get();  // This get method may cause blocking! Put him last
        System.out.println(o);
    }

}

class MyThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        // If there are time-consuming operations
        System.out.println("call()");
        return 1024;
    }

}

result:

Details:

1. With cache

2. The result may need to wait and block!

8. Common auxiliary classes (must focus)

8.1. Countdownlatch

Case: in the evening, the master closes the door of the study room

package com.kuang.juc.add;


import java.util.concurrent.CountDownLatch;

// Counter
public class CountDownLatchDemo {

    public static void main(String[] args) throws InterruptedException {
        // The total is six people in six classrooms
        // Use it when you have to perform a task
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 1; i <= 6; i++) {
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"go out");
                countDownLatch.countDown();  // Quantity - 1
            },String.valueOf(i)).start();
        }

        countDownLatch.await();  //Wait for the counter to return to zero, and then execute down!

        System.out.println("I'm your uncle. I'm closing the door!");
    }

}

result:

Principle:

countDownLatch.countDown() / / quantity - 1

countDownLatch.await() / / wait until the counter is reset to zero, and then execute downward!

Every time * * countDown() * * is called by a thread, the number is - 1, assuming that the counter becomes 0** countDownLatch.await() * * will be awakened and continue to execute downward!

8.2. Cyclicbarrier (addition counter)

Equivalent to addition counter

Case: gather 7 dragon balls to summon the divine dragon

package com.kuang.juc.add;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * eg: Gather 7 dragon balls to summon the dragon!
 */
public class CyclicBarrierDemo {

    public static void main(String[] args) {

        // Thread calling Dragon Ball
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("Summon dragon successfully!");
        });

        for (int i = 0; i < 7; i++) {
            // Can lamabda operate on variable i? no 
            final int temp = i;
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"Collected"+temp+"Dragon Ball");

                try {
                    cyclicBarrier.await();  //wait for
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }

            }).start();
        }

    }

}

8.3 semaphore

Case: grab a parking space

6 cars - 3 parking positions

package com.kuang.juc.add;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * Grab a parking space
 */
public class SemaphoreDemo {

    public static void main(String[] args) {
        // Number of threads, parking space current limit!!
        Semaphore semaphore = new Semaphore(3);

        for (int i = 1; i <= 6; i++) {
            new Thread(()->{
                // acquire() is released by release()

                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName()+"Grab a parking space");
                    TimeUnit.SECONDS.sleep(2);  // Simulated parking for 2s
                    System.out.println(Thread.currentThread().getName()+"Leave the parking space");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();
                }

            },String.valueOf(i)+"Car No").start();
        }

    }

}

result:

Principle:

semaphore.acquire(), assuming it is full, wait until it is released

semaphore.release() releases the current semaphore by + 1, and then wakes up the waiting thread!

Usage scenario:

1. Use when multiple shared resources are mutually exclusive!

2. Concurrent flow restriction, control the maximum number of threads!

9. Read write lock

9.1,ReadWriteLock

Reads can be read simultaneously by multiple threads

When writing, only one thread can write

package com.kuang.juc.rw;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * ReadWriteLock
 * Read -- read can coexist!
 * Reading and writing cannot coexist!
 * Write -- write cannot coexist!
 */
public class ReadWriteLockDemo {

    public static void main(String[] args) {
        //MyCache myCache = new MyCache();
        MyCacheLock myCache = new MyCacheLock();

        // 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();
        }
    }

}


// With read-write lock
class MyCacheLock{

    private volatile Map<String,Object> map = new HashMap<>();
    // Read / write lock, more fine-grained control!
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    // When saving and writing, you only want one thread to write at the same time
    public void put(String key,Object value){
        readWriteLock.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 complete");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    // When taking and reading, everyone can take and read
    // Note: if the read is not locked, the thread that may be read when writing will go in!!
    public void get(String key){
        readWriteLock.readLock().lock(); // Read lock
        try {
            System.out.println(Thread.currentThread().getName()+"read"+key);
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName()+"Read complete");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
    }

}


/**
 * Custom cache
 */
class MyCache{

    private volatile Map<String,Object> map = new HashMap<>();

    // Save, write
    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 complete");
    }

    // Take, read
    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 complete");
    }

}

Operation results:

Summary:

Exclusive lock: that is, the write lock here can only be occupied by one thread at a time!

Shared lock: that is, the read lock here can be occupied by multiple threads at the same time!

A read-write lock is a finer grained lock

10. Blocking queue

block

queue

BlockingQueue is not a new thing!

When do we use blocking queues?

1. Multithreaded concurrent processing

2. Thread pool

Learn to use queues

Add, remove, 4 sets of API s

modeThrow exceptionNo exception thrown, with return valueBlocking waitingTimeout wait
add toadd()offer()put()offer(,)
removeremove()poll()take()poll(,)
Determine queue header elementelement()peek()~~
/**
 * Throw exception
 */
public static void test1(){
    // Queue size
    ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

    System.out.println(blockingQueue.add("a"));
    System.out.println(blockingQueue.add("b"));
    System.out.println(blockingQueue.add("c"));

    // IllegalStateException: Queue full, the queue is full, throw an exception!
    //System.out.println(blockingQueue.add("d"));
    System.out.println("=========================");


    System.out.println(blockingQueue.remove());
    System.out.println(blockingQueue.element());  // View team leader element
    System.out.println(blockingQueue.remove());
    System.out.println(blockingQueue.remove());

    // java.util.NoSuchElementException has no element, throw an exception!
    // System.out.println(blockingQueue.remove());

}
/**
 * No exception thrown, return value!
 */
public static void test2(){
    //Queue size
    ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

    System.out.println(blockingQueue.offer("A"));
    System.out.println(blockingQueue.offer("B"));
    System.out.println(blockingQueue.offer("C"));
    // System.out.println(blockingQueue.offer("D"));  //  Return false, no exception thrown!

    System.out.println(blockingQueue.peek());  //Inspection team head element

    System.out.println(blockingQueue.poll());
    System.out.println(blockingQueue.poll());
    System.out.println(blockingQueue.poll());
    // System.out.println(blockingQueue.poll());  //  Return null, no exception thrown!

}
/**
 * Wait, block (always block)
 */
public static void test3(){

    ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

    // Always blocked
    try {
        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        // blockingQueue.put("d");  // There is no place in the queue. It has been blocked!
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());

        System.out.println(blockingQueue.take());  // Without this element, it has been blocked!
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}
/**
 * Wait, block (timeout wait)
 */
public static void test4() throws InterruptedException {

    ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);

    blockingQueue.offer("A");
    blockingQueue.offer("B");
    blockingQueue.offer("C");
    // blockingQueue.offer("D",2, TimeUnit.SECONDS);  //  Wait more than two seconds to exit!

    System.out.println("================================");

    System.out.println(blockingQueue.poll());
    System.out.println(blockingQueue.poll());
    System.out.println(blockingQueue.poll());
    blockingQueue.poll(2,TimeUnit.SECONDS);  // More than two seconds!

}

SynchronousQueue synchronization queue

Capacity 1

When you enter an element, you must wait for the element to be taken out before you can continue to put elements in it!

put,take

package com.kuang.juc.synbq;

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 you have an element, you must take it out first, otherwise you can't put in the value!
*/
public class SynchronousQueueDemo {

public static void main(String[] args) {

    BlockingQueue<String> blockingQueue = new SynchronousQueue<String>();  // Synchronization queue

    new Thread(()->{
        try {
            System.out.println(Thread.currentThread().getName()+"  put 1");
            blockingQueue.put("1");
            System.out.println(Thread.currentThread().getName()+"  put 2");
            blockingQueue.put("2");
            System.out.println(Thread.currentThread().getName()+"  put 3");
            blockingQueue.put("3");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    },"T1").start();

    new Thread(()->{
        try {
            TimeUnit.SECONDS.sleep(3);
            System.out.println(Thread.currentThread().getName()+"==>"+blockingQueue.take());
            TimeUnit.SECONDS.sleep(3);
            System.out.println(Thread.currentThread().getName()+"==>"+blockingQueue.take());
            TimeUnit.SECONDS.sleep(3);
            System.out.println(Thread.currentThread().getName()+"==>"+blockingQueue.take());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    },"T2").start();

}

}

Operation results:

be careful:

The synchronization queue is different from other blockingqueues

SynchronousQueue does not store elements

Put an element. You must take it from the inside first, otherwise you can't put in the value!

11. Thread pool (key)

Pool technology

The operation of the program, essence: occupy the resources of the system!

Want to optimize the use of resources! = = > Pool technology

Thread pool, connection pool, memory pool, object pool... Its creation and destruction consume system resources very much!

Pool technology: prepare some resources in advance and put them in the pool. If someone wants to use them, come to me and give them back to me after use!

Benefits of thread pool:

1. Reduce resource consumption

2. Increase the corresponding speed

3. Convenient management

One sentence summary: threads are reused, the maximum number of concurrent threads can be controlled, and it is convenient to manage threads

Thread pool: three methods

Alibaba development manual stipulates:

Three methods of testing

package com.kuang.juc.pool;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

// Executors tool class, 3 methods
public class Demo01 {

    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();  //  Elastic, strong in case of strength, weak in case of weakness

        try {
            for (int i = 1; i <= 100; i++) {
                // After using thread pool, thread pool is used to create threads
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+ " ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // When the thread pool runs out, the program ends. Close the thread pool!
            threadPool.shutdown();
        }

    }

}

The so-called three methods are three methods to create a thread pool:

  • Executors.newSingleThreadExecutor() / / create the thread pool of a single thread through the tool class
  • Executors.newFixedThreadPool(5) / / create a thread pool of size 5 through the tool class
  • Executors.newCachedThreadPool() / / created by tool class

7 parameters

Source code analysis:

// 1,Executors.newSingleThreadExecutor()
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}


// 2,Executors.newFixedThreadPool(5)
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}


// 3,Executors.newCachedThreadPool()
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,  // 2.1 billion OOM
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

// ThreadPoolExecutor(7 parameters) is called essentially
public ThreadPoolExecutor(int corePoolSize,  // Core thread pool size
                          int maximumPoolSize,  // Maximum thread pool size
                          long keepAliveTime,  // It will be released if no one calls it after timeout
                          TimeUnit unit,  // Timeout unit
                          BlockingQueue<Runnable> workQueue,  // Blocking queue
                          ThreadFactory threadFactory,  // Thread factory to create thread; Generally don't 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;
}

Diagram of 7 major parameters (simulating bank withdrawal)

The above illustrated story shows that when a person goes to the bank to withdraw money, he finds that only two windows are open, which are equivalent to the size of the core thread pool

Then he went to No. 1 to handle business. Another person came in. He saw that window No. 2 was empty and went to handle business,

A third man came. He found that three windows were not open and that someone was handling business in two windows

Just wait on the chair in the waiting area. The fourth person who comes in also waits in the waiting area. The fifth person who comes in also waits in the waiting area

When the waiting area is full at this time, it will trigger the bank to call the salesperson at windows 3, 4 and 5 to hurry back to work

At this time, salesmen 3, 4 and 5 came back

The waiting area here is equivalent to the blocking queue. When the blocking queue is full, the maximum thread pool mechanism will be triggered, that is, windows 3, 4 and 5 and windows 1 and 2 in front together form the maximum thread pool

At this time, the salesperson No. 3, 4 and 5 came back, and the three people in the waiting area went to handle business. At this time, the window is full, reaching the maximum thread pool size

Later, three more people came in and found that the window was full and entered the waiting area

At this time, the window is full and the waiting area is full

When another person suddenly comes in and he has no place to stay, the rejection strategy will be triggered

This person should choose to continue to wait, go back and forth, or drive the person at position 1 away

In the afternoon, there are very few people. There are few people in Windows 1 and 2. Windows 3, 4 and 5 have been empty for two hours, so they close the window first. After work, it is equivalent to a timeout in the thread pool. If no one calls, it will be released (keepAliveTime). The timeout does not wait

Create thread pool manually

// Custom thread pool! new ThreadPoolExecutor()
    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
            2,
            5,
            3,
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(3),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.DiscardOldestPolicy()  // When the queue is full, discard the oldest one in the queue and enter the queue instead of his position, and no exception will be thrown!
    );

4 rejection strategies

package com.kuang.juc.pool;


import java.util.concurrent.*;


/**
 * new ThreadPoolExecutor.AbortPolicy()   // When the bank is full and someone comes in, don't deal with this person. Throw an exception!
 * new ThreadPoolExecutor.CallerRunsPolicy()   // Where you come from, where you go! I won't accept it. Let the main thread accept it!
 * new ThreadPoolExecutor.DiscardPolicy()  // If the queue is full, no exception will be thrown. Lose the task and do not execute this thread!
 * new ThreadPoolExecutor.DiscardOldestPolicy()  // When the queue is full, discard the oldest one in the queue and enter the queue instead of his position, and no exception will be thrown!
 */
public class Demo01 {

    public static void main(String[] args) {

        // Custom thread pool! new ThreadPoolExecutor()
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardOldestPolicy()  // When the queue is full, discard the oldest one in the queue and enter the queue instead of his position, and no exception will be thrown!
        );

        try {
            // Max 8, max load = Deque + max
            // java.util.concurrent.RejectedExecutionException exceeds the maximum load. Throw an exception!
            for (int i = 1; i <= 9; i++) {
                // After using thread pool, thread pool is used to create threads
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+ " ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // When the thread pool runs out, the program ends. Close the thread pool!
            threadPool.shutdown();
        }

    }

}

Summary of four rejection strategies:

new ThreadPoolExecutor.AbortPolicy() / / when the bank is full and someone else comes in, we don't deal with this person and throw an exception * * (default)**

new ThreadPoolExecutor.CallerRunsPolicy() / / where you come from, where you go! I won't accept it. Let the main thread accept it!

new ThreadPoolExecutor.DiscardPolicy() / / if the queue is full, no exception will be thrown. Lose the task and do not execute this thread!

new ThreadPoolExecutor.DiscardOldestPolicy() / / when the queue is full, discard the oldest one in the queue and enter the queue instead of his position. No exception will be thrown!

Summary and expansion

Question: how to set the maximum size of the thread pool?

Understanding IO intensive and CPU intensive: (tuning)

// How should the maximum thread pool be specified?
    // 1. CPU intensive, several cores, just a few, can ensure the highest CPU efficiency!
    // 2. IO intensive > judge the threads that consume IO resources in your program!
    //    Program 15 large tasks io, very resource intensive!

    System.out.println(Runtime.getRuntime().availableProcessors());  // Get the number of cores of the computer cpu

    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
            2,
            Runtime.getRuntime().availableProcessors(),
            3,
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(3),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.DiscardOldestPolicy()  // When the queue is full, discard the oldest one in the queue and enter the queue instead of his position, and no exception will be thrown!
    );

12. Four functional interfaces (key points)

Programmers in the new era: lambda expression, chain programming, functional interface, Stream flow computing!

Functional interface: an interface with only one method

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

// Super functional interface
// lambda expression, chain programming, functional interface, Stream flow calculation! (jdk8 new features)
// Simplify the programming model and apply it in a large number in the new version of the framework!
// Foreach (functional interface with parameter of consumer type)

Code test:

1. Function functional interface

package com.kuang.juc.function;

import java.util.function.Function;

/**
 * Function Functional interface with one input parameter and one output parameter
 * As long as it is a functional interface, you can use lambda expression to simplify!
 */
public class Demo01 {

    public static void main(String[] args) {

        // Tool method: output the input value!
//        Function<String,String> function = new Function<String, String>() {
//            @Override
//            public String apply(String str) {
//                return str;
//            }
//        };

        Function<String,String> function = (str)->{ return str;};

        System.out.println(function.apply("lac"));

    }

}

2. Predicate type interface

package com.kuang.juc.function;

import java.util.function.Predicate;

/**
 * Assertive interface: there is an input parameter, and the return value can only be Boolean!
 */
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 str) {
//                return str.isEmpty();
//            }
//        };

        Predicate<String> predicate = (str)->{ return str.isEmpty(); };

        System.out.println(predicate.test(""));
    }

}

3. Consumer consumer interface

package com.kuang.juc.function;


import java.util.function.Consumer;

/**
 * Consumer interface: only input, no return value!
 */
public class Demo03 {

    public static void main(String[] args) {

//        Consumer<Integer> consumer = new Consumer<Integer>() {
//            @Override
//            public void accept(Integer integer) {
//                System.out.println(integer);
//            }
//        };

        Consumer<Integer> consumer = (i)->{ System.out.println(i); };

        consumer.accept(1024);

    }

}

4. Supplier supply interface

package com.kuang.juc.function;

import java.util.function.Supplier;

/**,
 * Supply type interface Supplier: only return values, no parameters
 */
public class Demo04 {

    public static void main(String[] args) {

//        Supplier<String> supplier = new Supplier<String>() {
//            @Override
//            public String get() {
//                return "xx-x";
//            }
//        };

        Supplier<String> supplier = ()->{ return "xx-x"; };
        System.out.println(supplier.get());
    }

}

13. Stream flow calculation

What is flow computing

Big data: storage + computing

Storage: the essence of mysql / collection is to store things;

All calculations are left to the flow to calculate!

package com.kuang.juc.stream;

import java.util.Arrays;
import java.util.List;

/**
 * Topic calculation: this problem can be completed in one minute and can only be realized with one line of code!
 * Now there are 5 users! Filter:
 * 1,ID Must be an even number
 * 2,Age must be greater than 23
 * 3,Convert user name to uppercase
 * 4,User names are sorted alphabetically backwards
 * 5,Output only one user's name!
 * 6,Output all information of the 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);

        // When converted to a collection, the collection is stored in tubes
        List<User> list = Arrays.asList(u1, u2, u3, u4, u5);

        // The calculation is given to the stream
        // lambda expression, chain programming, functional interface, Stream flow calculation! This question shows incisively and vividly!

        // 5. Output only one user's name!
//        list.stream()
//                .filter((u)->{return u.getId()%2 == 0;})
//                .filter((u)->{return u.getAge()>23;})
//                .map((u)->{return u.getName().toUpperCase();})
//                .sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
//                .limit(1)
//                .forEach(System.out::println);

        // 6. Output all information of the user!
        list.stream()
                .filter(u->{return u.getId()%2 == 0;})
                .filter(u->{return u.getAge()>23;})
                .map(u->{
                    u.setName(u.getName().toUpperCase());
                    return u;
                })
                .sorted((uu1,uu2)->{return uu2.getName().compareTo(uu1.getName());})
                .limit(1)
                .forEach(System.out::println);

        
    }

}

View the output of 5:

View the output of 6:

14,ForkJoin

Branch merge

What is ForkJoin

ForkJoin executes tasks in parallel in JDK 1.7 and 4! Improve efficiency and large amount of data!

Big data: Mapreduce divides big tasks into small tasks

Forkjoin features: job theft

This one maintains double ended queues!

ForkJoin

package com.kuang.juc.forkjoin;

import java.util.concurrent.RecursiveTask;

/**
 * The task of summation calculation!
 * 3000   6000 (ForkJoin)   9000 (Stream Parallel stream)
 *  How to use forkjoin
 *    1,ForkJoinPool Through him
 *    2,Calculate task forkjoinpool execute(ForkJoinTask task)
 *    3,The calculation class should inherit ForkJoinTask
 */
public class ForkJoinDemo extends RecursiveTask<Long> {

    private Long start;  // 0
    private Long end;  // 10_0000_0000

    // critical value
    private Long temp = 10000L;

    public ForkJoinDemo(Long start, Long end) {
        this.start = start;
        this.end = end;
    }

    // computing method
    @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;
            ForkJoinDemo task1 = new ForkJoinDemo(start, middle);
            task1.fork();  // Split tasks. Push task into thread queue
            ForkJoinDemo task2 = new ForkJoinDemo(middle+1, end);
            task2.fork();  // Split tasks. Push task into thread queue

            return task1.join() + task2.join();
        }
    }

}

Test class:

package com.kuang.juc.forkjoin;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.IntStream;
import java.util.stream.LongStream;

// 3000 6000 (forkjoin) 9000 (stream parallel stream)
public class Test {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // test1();   // Time: 5417
        // test2();   // Time: 3667
        // test3();   // Time: 182

    }

    // Ordinary programmer
    public static void test1(){
        Long sum = 0L;
        long startTime = System.currentTimeMillis();

        for (Long i = 1L; i < 10_0000_0000L; i++) {
            sum += i;
        }
        long endTime = System.currentTimeMillis();
        System.out.println("sum=>"+sum+"time:  "+(endTime-startTime));
    }

    // ForkJoin
    public static void test2() throws ExecutionException, InterruptedException {
        long startTime = System.currentTimeMillis();

        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Long> task = new ForkJoinDemo(0L, 10_0000_0000L);  //Specific task ForkJoinTask
        ForkJoinTask<Long> submit = forkJoinPool.submit(task);

        Long sum = submit.get();
        long endTime = System.currentTimeMillis();
        System.out.println("sum=>"+sum+"time:  "+(endTime-startTime));
    }

    // Stream parallel stream
    public static void test3(){
        long startTime = System.currentTimeMillis();

        long sum = LongStream.rangeClosed(0L, 10_0000_0000L).parallel().reduce(0, Long::sum);//(]

        long endTime = System.currentTimeMillis();
        System.out.println("sum=>"+sum+"time:  "+(endTime-startTime));
    }


}

ForkJoin usage scenario: use in a large amount of data! A small amount of data is not necessary!

15. Asynchronous callback

The original intention of Future design: to model the result of an event in the Future

package com.kuang.juc.future;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * Call Ajax asynchronously
 * // Asynchronous execution
 * // Successful callback
 * // Failed callback
 *
 */
public class Demo01 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // Asynchronous callback with no return value
//        CompletableFuture<Void> completableFuture = CompletableFuture. Runasync (() - > {/ / executes an asynchronous task without a return value
//            try {
//                TimeUnit.SECONDS.sleep(2);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName()+"runAsync=>Void");
//        });
//
//        System.out.println("0V0");
//        System.out.println(completableFuture.get());

        // Asynchronous callback with return value
        // ajax successful and failed callbacks
        // The error message is returned
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {  //Execute asynchronous task with return value
            System.out.println(Thread.currentThread().getName()+"=>supplyAsync=>String");
            int i = 10/0;
            return "Shatter the darkness with thunder";
        });

        // Compilation succeeded!
        System.out.println(completableFuture.whenComplete((t, u) -> {
            System.out.println("t=>" + t);  // t represents the normal return result
            System.out.println("u=>" + u); // u stands for error message
        }).exceptionally((e) -> {  //Compilation failed
            System.out.println(e.getMessage());
            return "Two cups";
        }).get());


    }

}

Check the result: no exception, correct output result:

If there is an exception in the program, run it again:

16,JMM

Please talk about your understanding of Volatile

Volatile is a lightweight synchronization mechanism provided by Java virtual machine

1. Ensure visibility

2. Atomicity is not guaranteed

3. Prohibit instruction rearrangement

What is JMM

JMM: it's a Java memory model. It doesn't exist. It's a concept and model!

Some synchronization conventions of JMM:

1. Before the thread is unlocked, the shared variables of the thread must be flushed back to main memory immediately

2. Before a thread locks, it must read the latest value in the main memory into its own working memory

3. Locking and unlocking are the same lock

Thread working memory main memory

8 operations in JMM

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

Problem: the program does not know that the value in main memory has changed

17,Volatile

1. Ensure visibility

package com.kuang.juc.Tvolatile;

import java.util.concurrent.TimeUnit;

public class JMMDemo {

    // Without volatile, the program will loop
    // Visibility can be guaranteed!
    private volatile static int num = 0;

    public static void main(String[] args) {  //main

        new Thread(()->{  //Thread 1 does not know the change of main memory!
            while (num==0){

            }
        },"1").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 when executing tasks. It either succeeds or fails at the same time!

package com.kuang.juc.Tvolatile;


// Atomicity is not guaranteed
public class VDemo02 {

    // volatile does not guarantee atomicity!
    private volatile static int num = 0;

    public static void add(){
        num++;
    }

    public static void main(String[] args) {

        // Theoretically, the output should be 2w
        for (int i = 1; i <= 20; i++) {
            new Thread(()->{
                for (int j = 0; j < 1000; j++) {
                    add();
                }
            }).start();
        }

        while (Thread.activeCount()>2){  //main  gc
            // Comity, re compete for resources!
            Thread.yield();
        }

        System.out.println(Thread.currentThread().getName()+"  "+num);

    }

}

The output is less than 2w, there is a problem!

Question: how to ensure atomicity without synchonized and lock?

Use atomic classes to solve atomic problems

package com.kuang.juc.Tvolatile;


import java.util.concurrent.atomic.AtomicInteger;

// Atomicity is not guaranteed
public class VDemo02 {
    
    private static AtomicInteger num = new AtomicInteger();  //Integer of atomic class

    public static void add(){
        num.getAndIncrement();  // AtomicInteger +1 method, CAS used at the bottom
    }

    public static void main(String[] args) {

        // Theoretically, the output should be 2w
        for (int i = 1; i <= 20; i++) {
            new Thread(()->{
                for (int j = 0; j < 1000; j++) {
                    add();
                }
            }).start();
        }

        while (Thread.activeCount()>2){  //main  gc
            // Comity, re compete for resources!
            Thread.yield();
        }

        System.out.println(Thread.currentThread().getName()+"  "+num);

    }

}

View run results:

The bottom of these classes are directly linked to the operating system! Modify the value directly in memory!

Unsafe class is a very special existence!

Instruction rearrangement

What is instruction rearrangement: the program you write is not executed by the computer in the order you write!

Source code - > compiler optimization rearrangement – > instruction parallelism may also rearrange – > memory system may also rearrange – > execution

When the processor executes instruction rearrangement, it considers the dependence between data

int x = 1;  //1
int y = 2;  //2
x = x + 5;  //3
y = x * x;  //4

//What we expect: 1234   
//When the program is executed, it may be 1324 2134 2413
//Could it be: 4123

Possible impact results: the default values of premise a, b, x and y are 0

Thread AThread B
x=ay=b
b=1a=2

Normal results: x = 0, y = 0;

If an instruction rearrangement occurs:

Thread AThread B
b=1a=2
x=ay=b

The instruction rearrangement has a strange result: x=2, y=1;

Instruction rearrangement understanding

Adding volatile keyword can avoid instruction rearrangement!

Memory barrier. That is, CPU instructions. Its role:

1. Ensure the execution sequence of specific operations!

2. Memory visibility of some variables can be guaranteed (with these features, volatile achieves visibility)

Volatile can maintain visibility and cannot guarantee atomicity. Due to memory barrier, it can avoid instruction rearrangement

18. Completely play with singleton mode

Hungry man, DCL lazy man, deep study!

Hungry Han style

package com.kuang.juc.single;

// Hungry Han style single case
public class Hungry {

    // It may waste space
    private byte[] data1 = new byte[1024*1024];
    private byte[] data2 = new byte[1024*1024];
    private byte[] data3 = new byte[1024*1024];
    private byte[] data4 = new byte[1024*1024];

    private Hungry(){

    }

    private final static Hungry HUNGRY = new Hungry();

    public static Hungry getInstance(){
        return HUNGRY;
    }

}

DCL lazy

package com.kuang.juc.single;


import com.sun.org.apache.regexp.internal.RE;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

// Lazy singleton mode
public class LazyMan {

    // Flag bit
    private static boolean panghu = false;

    // Lock to prevent Decompilation
    private LazyMan(){
        synchronized (LazyMan.class){
            if (panghu==false){
                panghu = true;
            }else {
                throw new RuntimeException("Do not attempt to use reflection to break exceptions");
            }
        }
    }

    private volatile static LazyMan lazyMan;  // Avoid instruction rearrangement

    // Lazy single case DCL with dual detection lock mode
    private static LazyMan getInstance(){
        if (lazyMan==null){
            synchronized (LazyMan.class){
                if (lazyMan==null){
                    lazyMan = new LazyMan();  // Not atomic operation
                    /**
                     * 1,Allocate memory space
                     * 2,Execute the construction method and initialize the object
                     * 3,Point this object to this space
                     *
                     * 123
                     * 132 A
                     *     B  //At this time, LazgyMan has not completed the construction
                     */
                }
            }
        }

        return lazyMan;
    }

    //Reflection!
    public static void main(String[] args) throws Exception {

        // 1. Use reflection destruction to solve the problem of private structure and locking
//        LazyMan instance1 = LazyMan.getInstance();
//        //1. Get reflection object
//        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
//        declaredConstructor.setAccessible(true);  // Ignore private constructors
//        LazyMan instance2 = declaredConstructor.newInstance();  // Create objects by reflection
//
//        System.out.println(instance1);
//        System.out.println(instance2);

        // 2. Directly create two objects through reflection and add flag bit to solve!
//        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
//        declaredConstructor.setAccessible(true);  // Ignore private constructors
//        LazyMan instance1 = declaredConstructor.newInstance();  // Create objects by reflection
//        LazyMan instance2 = declaredConstructor.newInstance();  // Create objects by reflection
//
//        System.out.println(instance1);
//        System.out.println(instance2);

        // 3. If the flag bit is decompiled, you know, it is cracked again
        Field panghu = LazyMan.class.getDeclaredField("panghu");
        panghu.setAccessible(true);

        Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);  //Ignore private constructors
        LazyMan instance1 = declaredConstructor.newInstance();  //Create objects by reflection

        panghu.set(instance1,false);

        LazyMan instance2 = declaredConstructor.newInstance();  //Create objects by reflection

        System.out.println(instance1);
        System.out.println(instance2);

    }

}

// Double check lock mode description:
// This method first determines whether the variable is initialized or not, and then obtains the lock.
// After obtaining the lock, judge whether the variable is initialized again.
// The purpose of the second judgment is that it is possible that other threads have obtained locks and initialized variables. The variables will not be initialized until the second check is passed.

// This method checks and determines twice and uses the lock, so the image is called double check lock mode.

Static inner class

package com.kuang.juc.single;


//Static memory class
public class Holder {

    private Holder(){

    }

    public static Holder getInstance(){
        return InnerClass.holder;
    }

    public static class InnerClass{
        private static final Holder holder = new Holder();
    }

}

Single case is unsafe and there is reflection

Enumeration is on the stage

package com.kuang.juc.single;


import java.lang.reflect.Constructor;

// Enumeration itself is also a class class
public enum  EnumSingle {

    INSTANCE;

    public EnumSingle getInstance(){
        return INSTANCE;
    }


}

class Test{

    // Attempt to crack enumeration through reflection
    public static void main(String[] args) throws Exception {
        EnumSingle instance1 = EnumSingle.INSTANCE;
        Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
        declaredConstructor.setAccessible(true);
        EnumSingle instance2 = declaredConstructor.newInstance();

        // Appears: Java lang.NoSuchMethodException: com. kuang. juc. single. EnumSingle.< Init > () has no empty argument constructor
        System.out.println(instance1);
        System.out.println(instance2);
    }

}

It is not a parameterless structure, but a parameterless structure with two parameters!

Through decompilation, it was found that it deceived us

Use JAD Exe to decompile

**The final decompiled source code of enumeration types: * * it is found that she has a two parameter construction method, not an empty parameter construction method

package com.kuang.juc.single;


public final class EnumSingle extends Enum
{

    public static EnumSingle[] values()
    {
        return (EnumSingle[])$VALUES.clone();
    }

    public static EnumSingle valueOf(String name)
    {
        return (EnumSingle)Enum.valueOf(com/kuang/juc/single/EnumSingle, name);
    }

    private EnumSingle(String s, int i)
    {
        super(s, i);
    }

    public EnumSingle getInstance()
    {
        return INSTANCE;
    }

    public static final EnumSingle INSTANCE;
    private static final EnumSingle $VALUES[];

    static 
    {
        INSTANCE = new EnumSingle("INSTANCE", 0);
        $VALUES = (new EnumSingle[] {
            INSTANCE
        });
    }
}

Again, through the two parameter construction method, the reflection attempts to crack, and it is found that:

19. Deep understanding of CAS

What is CAS

package com.kuang.juc.cas;

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {

    // CAS compareandset: compare and exchange!
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);

        // Expectations, updates
        //  public final boolean compareAndSet(int expect, int update)
        // If my expected value is reached, update it, otherwise don't update it! CAS is the concurrency primitive of CPU!!
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());
        
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());

    }

}

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, it will cycle all the time (the bottom layer is spin lock)

Disadvantages:

1. The cycle takes time

2. One time can only guarantee the atomicity of one shared variable

3. ABA problem

CAS: ABA problem (civet cat for Prince)

package com.kuang.juc.cas;

import java.util.concurrent.atomic.AtomicInteger;

public class CASDemo {

    // CAS compareandset: compare and exchange!
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);

        // For the sql we usually write: optimistic lock!
        
        // Expectations, updates
        //  public final boolean compareAndSet(int expect, int update)
        // If my expected value is reached, update it, otherwise don't update it! CAS is the concurrency primitive of CPU!!

        //  =====================Troublemaker thread===========================
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());

        System.out.println(atomicInteger.compareAndSet(2021, 2020));
        System.out.println(atomicInteger.get());

        //  =====================Expected thread===========================
        System.out.println(atomicInteger.compareAndSet(2020, 6666));
        System.out.println(atomicInteger.get());

    }

}

How to solve this problem: using atomic references

20. Atomic reference

Solve the ABA problem and introduce atomic reference! Corresponding thought optimistic lock!

Atomic operation with version number! (equivalent to optimistic lock in sql)

be careful:

package com.kuang.juc.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 {

    // CAS compareandset: compare and exchange!
    public static void main(String[] args) {

        // Pit: AtomicStampedReference
        // Note: if the generic is a wrapper class, pay attention to the reference of the object!
        
        // For normal business operations, objects are compared one by one! 
        AtomicStampedReference<Integer> atomicReference = new AtomicStampedReference<Integer>(1,1);

        new Thread(()->{

            int stamp = atomicReference.getStamp();  //Get the initial version number 1
            System.out.println("a1=>"+stamp);

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // version + 1
            System.out.println(atomicReference.compareAndSet(1, 2, atomicReference.getStamp(), atomicReference.getStamp()+1));
            System.out.println("a2=>"+ atomicReference.getStamp());

            System.out.println(atomicReference.compareAndSet(2, 1, atomicReference.getStamp(), atomicReference.getStamp()+1));
            System.out.println("a3=>"+ atomicReference.getStamp());

        },"a").start();

        // Same principle as optimistic lock
        new Thread(()->{

            int stamp = atomicReference.getStamp();  //Get the original version number 1
            System.out.println("b1=>"+stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(atomicReference.compareAndSet(1, 6, stamp, stamp + 1));
            System.out.println("b2=>"+atomicReference.getStamp());

        },"b").start();

    }

}

View results:

21. Understanding of various locks

1. Fair lock, unfair lock

Fair lock: very fair. You can't jump the queue. You must come first!

Unfair lock: it's very unfair. You can jump the queue (all unfair 3h 3s by default) to ensure efficiency!

public ReentrantLock() {
    sync = new NonfairSync();
}

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

2. Reentrant lock

Reentrant lock (recursive lock)

Synchonized version reentrant lock

package com.kuang.juc.lock;

import java.util.concurrent.TimeUnit;

/**
 * Synchonized Version of reentrant lock
 */
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");
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        call();  // There are locks here, too
    }

    public synchronized void call(){
        System.out.println(Thread.currentThread().getName()+" call");
    }

}

Lock version reentrant lock

package com.kuang.juc.lock;


import java.util.concurrent.TimeUnit;
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: lock lock();    lock. unlock();
        // lock locks must be paired, or they will die inside
        try {
            System.out.println(Thread.currentThread().getName()+" sms");
            TimeUnit.SECONDS.sleep(3);
            call();  // There are locks here, too
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void call(){
        lock.lock(); // Details: lock lock();    lock. unlock();
        try {
            System.out.println(Thread.currentThread().getName()+" call");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

summary

Reentrant lock means that a thread has obtained a lock and can obtain the lock again without deadlock!

3. Spin lock

What is spin lock

Let's define a spin lock ourselves

package com.kuang.juc.lock;

import java.util.concurrent.atomic.AtomicReference;

/**
 * Custom spin lock
 */
public class Spinlock {

    // int defaults to 0
    // Thread defaults to null
    AtomicReference<Thread> atomicReference = new AtomicReference<>();

    // Lock
    public void mylock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"===> mylock");

        // Spin lock
        while (!atomicReference.compareAndSet(null,thread)){

        }
    }


    // Unlock
    public void myUnlock(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+"===> myUnlock");

        // Spin lock
        atomicReference.compareAndSet(thread,null);
    }

}

Custom spin lock for testing:

package com.kuang.juc.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestSpinlock {


    public static void main(String[] args) throws InterruptedException {

//        Lock lock = new ReentrantLock();
//        lock.lock();
//        lock.unlock();

        // Use custom spin lock to realize CAS at the bottom
        Spinlock spinlock = new Spinlock();


        new Thread(()->{
            spinlock.mylock();
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                spinlock.myUnlock();
            }

        },"T1").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(()->{
            spinlock.mylock();
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                spinlock.myUnlock();
            }

        },"T2").start();

    }

}

result:

explain:

1. The T1 above gets the lock first. After getting the lock, judge that the Thread object is empty and change the object into the current Thread object without spin

2. T2 Thread comes in. The Thread object is not empty. When the while loop condition is true, T2 is always in the spin state

3. After T1 unlocks, T2 finds that the Thread object is reset to null. When the while condition is not met, the spin ends, and T2 unlocks again!

4. Deadlock

What is a deadlock

Deadlock test, how to eliminate deadlock!

package com.kuang.juc.lock;

import java.util.concurrent.TimeUnit;

public class DeadLockDemo {

    public static void main(String[] args) {

        String LockA="A";
        String LockB="B";

        new Thread(new MyThread(LockA,LockB),"thread  a").start();
        new Thread(new MyThread(LockB,LockA),"thread  b").start();
    }

}

class MyThread implements Runnable{

    private String LockA;

    private String LockB;

    public MyThread(String lockA, String lockB) {
        LockA = lockA;
        LockB = lockB;
    }

    @Override
    public void run() {

        synchronized (LockA){

            System.out.println(Thread.currentThread().getName()+"  Lock:" +LockA+"Trying to get"+LockB);

            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (LockB){
                System.out.println(Thread.currentThread().getName()+"  Lock:" +LockB+"Trying to get"+LockA);
            }

        }

    }
}

result:

A deadlock has occurred

reason:

1. LockA and LockB in the constant pool are locked

2. When thread a comes in, it assigns a value to it. After the assignment, LockA=A and LockB=B in the constant pool are locked. When LockA=A in thread a, it gets the lock of a and tries to get the lock of B

3. After thread B comes in, LockA=B in thread B gets the lock of B and tries to get the lock of A

4. This is a deadlock!

solve the problem

1. Use jps -l to locate the process number

2. Use jstack process number to view the stack information of Deadlock:

Troubleshooting during interview or work:

1. Look at the log 9

2. Look at the stack information! one

explain
This course is from the JUC of the crazy talk java series: https://www.bilibili.com/video/BV1B7411L7tE The course is of high quality. Welcome to study.
I wrote this note one by one in class

Topics: JUC