Crazy god said JUC bi bi li video link address: www.bilibili.com/video/BV1B7…


1. What is JUC

JUC is toolkits, packages, categories, etc. under java.util.

Common thread code:

  • Thread
  • Runnable has no return value and is relatively inefficient compared to Callable.
  • Callable has a return value!

2. Threads and processes

Threads, processes, if you can’t use a one-sentence spoken technology, not solid!

  • Process: a program, qi.exe music.exe program collection;
  • A process can often contain multiple threads, at least one!
  • Java has 2 threads by default? Mian, GC,
  • Thread: opened a process Typora, write, autosave (thread responsible)
  • For Java it provides:Thread, Runnable, and CallableManipulate threads.

Can Java really start threads? The answer is: no!

public synchronized void start(a) {
    /** * 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 */}}}// the local method, the underlying operation is C++, Java cannot directly manipulate the hardware
private native void start0(a);
Copy the code

Concurrent, parallel

Concurrent programming: concurrent, parallel

Concurrency (multiple threads working on the same resource)

  • A core CPU, simulated out of multiple threads, fast alternating.

Parallel (more than one person walking together)

  • Multi-core CPU, multiple threads can execute simultaneously; Eg: Thread pool!
public class Test1 { 
    public static void main(String[] args) { 
	  // Get the number of CPU cores
     // CPU intensive, IO intensive
  	  System.out.println(Runtime.getRuntime().availableProcessors());
     // If the computer has 8 cores, the result output is 8}}Copy the code

The essence of concurrent programming: Make full use of CPU resources

Threads have several states (6)

public enum State {
    /** * Thread state for a Thread which has not yet started
    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
    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
     * {@linkObject#wait() object.wait}. * Thread blocking status */
    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>{@linkLockSupport#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,
    /**
     * 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>{@linkLockSupport#parkUntil locksupport. parkUntil}</li> * </ul> * Thread timeout wait status, after a certain amount of time will not wait */
    TIMED_WAITING,
    /** * Thread state for a terminated Thread. * The Thread has completed execution
    TERMINATED;
}
Copy the code

Wait/sleep

1. They come from different classes

  • wait => Object
  • sleep => Thread

2. Release of locks

  • Wait releases the lock
  • Hold the lock to sleep, will not release!

3. The scope of use is different

  • Wait must be used in synchronized code blocks
  • Sleep can sleep anywhere

3, Synchronized lock

Traditional Synchronized lock

Let’s look at an example of multi-threaded ticket selling

package com.haust.juc01;

/* * @auther: csp1999 * @date: 2020/07/21/13:59 * @description: ticket example */
public class SaleTicketTDemo01 {

    /* * A thread is a single resource class with no operations attached to it! * 1, properties, methods */
    public static void main(String[] args) {
        // Concurrency: multiple threads operate on a resource class at the same time, throwing the resource class into the thread
        Ticket ticket = new Ticket();

        // @functionalInterface, jdk1.8 lambada expression
        new Thread(() -> {
            for (int i = 1; i < 50; i++) { ticket.sale(); }},"A").start();

        new Thread(() -> {
            for (int i = 1; i < 50; i++) { ticket.sale(); }},"B").start();

        new Thread(() -> {
            for (int i = 1; i < 50; i++) { ticket.sale(); }},"C").start(); }}// Resource class OOP
class Ticket {
    // Attributes, methods
    private int number = 50;

    // The way tickets are sold
    // synchronized
    public synchronized void sale(a) {
        if (number > 0) {
            System.out.println(Thread.currentThread().getName() + "Sold out" +
                    (50-(--number)) + "One ticket, the rest :" + number + "Ticket"); }}}Copy the code

4, Lock up

The Lock interface

  • Fair lock: Very fair, threads are executed in first-come-first-served order
  • Unfair lock: Very unfair: Can cut in line (default lock)

Replace synchronized with lock in the ticket example above:

package com.haust.juc01;

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

/* * @auther: csp1999 * @date: 2020/07/21/13:59 * @description: Ticket example 2 */
public class SaleTicketTDemo02 {

    public static void main(String[] args) {
        
        // Concurrency: multiple threads operate on a resource class at the same time, throwing the resource class into the thread
        Ticket2 ticket = new Ticket2();

        // @functionalInterface, jdk1.8 lambada expression
        new Thread(() -> {
            for (int i = 1; i < 50; i++) { ticket.sale(); }},"A").start();

        new Thread(() -> {
            for (int i = 1; i < 50; i++) { ticket.sale(); }},"B").start();

        new Thread(() -> {
            for (int i = 1; i < 50; i++) { ticket.sale(); }},"C").start(); }}/ / Lock 3 steps
// 1. new ReentrantLock();
// 2. Lock. Lock ()
// 3. Lock. Unlock (
class Ticket2 {
    // Attributes, methods
    private int number = 50;

    Lock lock = new ReentrantLock();

    // How to sell tickets
    public void sale(a) {

        lock.lock();/ / lock

        try {
            // Business code
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "Sold out" +
                        (50 - (--number)) + "One ticket, the rest :" + number + "Ticket"); }}catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();/ / unlock}}}Copy the code

Synchronized and Lock:

  • 1, Synchronized built-in Java keyword, Lock is a Java class
  • 2. Synchronized cannot determine the state of obtaining a Lock. Lock can determine whether a Lock is obtained
  • 3, Synchronized will automatically release the lock, lock must be manually released lock! If the lock is not released, a deadlock occurs
  • Synchronized thread 1 (acquire lock, if thread 1 blocks), thread 2 (wait, dumb, etc.) Lock will not necessarily wait;
  • 5, Synchronized can re-enter the lock, can not interrupt, not fair; Lock, reentrant Lock, can judge Lock, not fair (can set themselves);
  • 6, Synchronized suitable for locking a small number of code synchronization problems, Lock suitable for locking a large number of synchronization code!

What is a lock, how to determine what is locked!

This problem will be analyzed with examples later.

5. Producer and consumer issues

Common interview questions: singleton patterns, sorting algorithms, producers and consumers, deadlocks

Synchronized edition of producer and consumer issues

package com.haust.pc;

/** * Communication issues between threads: producer and consumer issues! 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++) {
                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(); }}// Determine wait, business, notification
class Data { // Digital resource class

    private int number = 0;

    / / + 1
    public synchronized void increment(a) throws InterruptedException {
        Increment (); increment(); increment(); increment(); increment(); increment() If =0, a. wait() waits (wait() releases the lock), and C tries to execute the production method, but still checks number! =0, then b. wait() waits (wait() releases the lock). It happens that the consumer thread B/D consumes a product, making number=0, and then calls this.notifyall () after B/D consumes; The producer thread continues to wait(), and the consumer calls this.notifyall (). The producer thread waits () and the consumer calls this.notifyall (). Producers then continue to produce ahead of themselves, eventually leading to 'excess capacity', where number is greater than 1 if(number! = 0){// wait this.wait(); } * /
        while(number ! =0) { // Note that you can't use "if" or false wake up will occur
            / / wait for
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "= >" + number);
        // Notify other threads that I +1 is done
        this.notifyAll();
    }

    / / 1
    public synchronized void decrement(a) throws InterruptedException {
        while (number == 0) {
            / / wait for
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "= >" + number);
        // Notify other threads that I am done with -1
        this.notifyAll(); }}Copy the code

There is A problem, A B C D 4 threads! False awaken

First go to the java.lang package of the CHM documentation to find Object, and then go to the wait() method:

Therefore, while judgment must be used in the above code, not if

JUC edition of producer and consumer issues

Condition is found by Lock in the official documentation

Click on Condition to check

Code implementation:

package com.haust.pc;

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

/** * Communication issues between threads: producer and consumer issues! 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(); }}// Determine wait, business, notification
class Data2 { // Digital resource class

    private int number = 0;

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

    //condition.await(); / / wait for
    //condition.signalAll(); // Wake up all
    / / + 1
    public  void increment(a) throws InterruptedException {

        lock.lock();
        try {
            // Business code
            while(number ! =0) {
                / / wait for
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "= >" + number);
            // Notify other threads that I +1 is done
            condition.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally{ lock.unlock(); }}/ / 1
    public  void decrement(a) throws InterruptedException {
        lock.lock();
        try {
            while (number == 0) {
                / / wait for
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "= >" + number);
            // Notify other threads that I am done with -1
            condition.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally{ lock.unlock(); }}}Copy the code

Any new technology does not just cover the original technology, it has its advantages and complement to the old technology!

Condition notifies and wakes up threads precisely

The running results of the above code are shown as follows:

Question: The order of ABCD thread preemption is random. How can we improve the code if we want ABCD threads to execute in order?

Code implementation:

package com.haust.pc;

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

/* * A calls B, B calls C, and C calls 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 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; 
    // number=1 A number=2 B Number =3 C

    public void printA(a) {
        lock.lock();
        try {
            // Business, judge -> execute -> notify
            while(number ! =1) {
                / / A wait
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>AAAAAAA");
            // Wake up the specified person, B
            number = 2;
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally{ lock.unlock(); }}public void printB(a) {
        lock.lock();
        try {
            // Business, judge -> execute -> notify
            while(number ! =2) {
                / / wait for B
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>BBBBBBBBB");
            // Wake up the specified person, c
            number = 3;
            condition3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally{ lock.unlock(); }}public void printC(a) {
        lock.lock();
        try {
            // Business, judge -> execute -> notify
            // Business, judge -> execute -> notify
            while(number ! =3) {
                / / C waiting
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName() + "=>CCCCC ");
            // Wake up the specified person, A
            number = 1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally{ lock.unlock(); }}}Copy the code

Test results:

6. 8 Locking

Put forward a problem in front: how to judge who is locked! Know what a lock is and who the lock is!

Deep understanding of our locks

The object of a synchronized lock is the caller of a method

Code Example 1:

package com.haust.lock8;

import java.util.concurrent.TimeUnit;

1, Under standard conditions, two lines print first send SMS or print first make a phone call? 1, sendSms delay 4 seconds, two lines print first sendSms or call? 1/ Text message 2/ call */.
public class Test1 {
    public static void main(String[] args) {
        Phone phone = new Phone();

        // The lock exists
        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{

    // Synchronized lock objects are method callers! ,
    // Both methods are called with the same object (the same lock). Whoever gets the lock first executes it!
    public synchronized void sendSms(a){
        try {
            TimeUnit.SECONDS.sleep(4);// Hold the lock to sleep
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Texting");
    }

    public synchronized void call(a){
        System.out.println("Make a call"); }}// Send SMS messages first, then make phone calls
Copy the code

Normal method has no lock! If the method is not synchronized, it is not affected by the lock and executes normally

Code Example 2:

package com.haust.lock8;

import java.util.concurrent.TimeUnit;

/** * 3, add a normal method after! SMS or Hello first? // Common methods * 4, two objects, two synchronization methods, SMS or call? // Call */
public class Test2  {
    public static void main(String[] args) {
        // Two objects, two callers, two locks!
        Phone2 phone1 = new Phone2();
        Phone2 phone2 = new Phone2();

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

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

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

    // Synchronized lock objects are method callers!
    public synchronized void sendSms(a){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Texting");
    }

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

    // There is no lock here! Non-synchronous methods are not affected by locks
    public void hello(a){
        System.out.println("hello"); }}// Make a call first, then hello, and finally send a message
Copy the code

** There is only one Class template for each instance of an object

Code Example 3:

package com.haust.lock8;

import java.util.concurrent.TimeUnit;

/** * 5, add two static synchronization methods, only one object, print first send SMS? Make a phone call? * 6, Two objects! Add two static synchronization methods, print first and send SMS? Make a phone call? * /
public class Test3  {
    public static void main(String[] args) {
        // There is only one Class template for two objects
        Phone3 phone1 = new Phone3();
        Phone3 phone2 = new Phone3();

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

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

        new Thread(()->{
            phone2.call();
        },"B").start(); }}// Phone3 has a unique Class object
class Phone3{

    // Synchronized lock objects are method callers!
    // static static method
    // The class is available as soon as it is loaded. Lock is a Class
    public static synchronized void sendSms(a){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Texting");
    } 

    public static synchronized void call(a){
        System.out.println("Make a call"); }}// Send SMS messages first, then make phone calls
Copy the code

Code Example 4:

package com.haust.lock8;

import java.util.concurrent.TimeUnit;

/** * 7, 1 static synchronization method, 1 normal synchronization method, 1 object, print first send SMS? Make a phone call? * 8, 1 static synchronization method, 1 ordinary synchronization method, two objects, first print SMS? Make a phone call? * /
public class Test4  {
    public static void main(String[] args) {
        // There is only one Class template for two objects
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();
        // The lock exists
        new Thread(()->{
            phone1.sendSms();
        },"A").start();

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

        new Thread(()->{
            phone2.call();
        },"B").start(); }}// Phone3 has a unique Class object
class Phone4{

    // Static synchronized methods lock Class templates
    public static synchronized void sendSms(a){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Texting");
    }

    // The caller (object) of a normal synchronized method lock, which has a different object, so there is no need to wait
    public synchronized void call(a){
        System.out.println("Make a call"); }}// 7/8 In both cases, the phone call is executed first and the SMS message is executed later, because the objects of the two locks are different.
// Static synchronization locks the Class template. Normal synchronization locks the instantiated object.
// Instead of waiting for the former to unlock before the latter can be executed, the two can be executed in parallel because SMS sleep lasts for 4s
// So call first.
Copy the code

summary

  • New This Specifies a mobile phone
  • Static Class unique template

7. Collection classes are unsafe

The List is not safe

* * List, ArrayList, and so on under the condition of simultaneous multi-threading, cannot realize data sharing, when multiple threads at the same time call a List object will appear abnormal ConcurrentModificationException concurrent modification * *.

Code examples:

package com.haust.unsafe;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/ / Java. Util. ConcurrentModificationException concurrent modification exception!
public class ListTest {
    public static void main(String[] args) {
        // Synchronized;
        /* * Solution; List
      
        List = new Vector<>(); * scheme 2, a List < String > List = * Collections in synchronizedList (new ArrayList < > ()); List
       
         List = new CopyOnWriteArrayList<>(); * /
       
      
        
       /* CopyOnWrite An optimization strategy in computer programming for copy-on-write; * Fixed, write (overwrite) when read by multiple threads * Avoid overwrite when written, causing data problems! Where is CopyOnWriteArrayList more than Vector Nb? * /	
        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(); }}}Copy the code

CopyOnWriteArrayList source code analysis reference

The Set is not safe

* * the Set, the Hash, etc under the condition of simultaneous multi-threading, cannot realize data sharing, when multiple threads at the same time call a Set object will appear abnormal ConcurrentModificationException concurrent modification * *.

Code examples:

package com.haust.unsafe;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

/** * Abnormal ConcurrentModificationException concurrent modification * 1, Set the < String > Set = * Collections. SynchronizedSet (new HashSet < > ()); *, *, / 2
public class SetTest {
    public static void main(String[] args) {
        //Set
      
        set = new HashSet<>(); / / not safe
      
        
        // Set
      
        set = Collections.synchronizedSet(new HashSet<>()); / / security
      
        Set<String> set = new CopyOnWriteArraySet<>();/ / security

        for (int i = 1; i <=30 ; i++) {
           new Thread(()->{
               set.add(UUID.randomUUID().toString().substring(0.5)); System.out.println(set); },String.valueOf(i)).start(); }}}Copy the code

Extension: What is underneath a hashSet?

You can see that the underlying HashSet is a HashMap

HashMap source code analysis reference

The Map is not safe

Review the basic Map operations:

Code examples:

package com.haust.unsafe;

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

// ConcurrentModificationException
public class  MapTest {

    public static void main(String[] args) {
        // Is map used in this way? No, we don't use hashMaps at work
        // What is the default equivalent? New HashMap < > (16,0.75);
        // Map<String, String> map = new HashMap<>();
        // Extension: Investigate the principle of 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(); }}}Copy the code

8. Callable (simple)

Callable vs. Runable:

For example, if Callable is you and you want to meet your girlfriend **Runable **, her best friend Thread

  • Callable is an interface under Concurrent under the java.util package that returns a value and can throw checked exceptions
  • Runable is an interface under the java.lang package that returns no value and cannot throw checked exceptions
  • Run ()/ call()

The difference between Lock and Synchronized is that the former is an interface under java.util and the latter is a keyword under java.lang.

The code for

package com.haust.callable;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/** * 1, ** * 2, */
public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // new Thread(new Runnable()).start(); / / start a Runnable
        // new Thread(new FutureTask<V>()).start();
        // new Thread(new FutureTask<V>( Callable )).start();
        new Thread().start(); // How to start Callable?

        // new an instance of MyThread
        MyThread thread = new MyThread();
        // The MyThread instance goes into FutureTask
        FutureTask futureTask = new FutureTask(thread); / / class

        new Thread(futureTask,"A").start();
        new Thread(futureTask,"B").start(); // The call() method results are cached for efficiency, so only one call is printed

        // The get method may block! Put him to the end
        Integer o = (Integer) futureTask.get(); 
        // Or use asynchronous communication to handle!
        System.out.println(o);/ / 1024}}class MyThread implements Callable<Integer> {

    @Override
    public Integer call(a) {
        System.out.println("call()"); // How many calls do threads A and B print? (1)
        // Time-consuming operation
        return 1024; }}//class MyThread implements Runnable {
//
// @Override
// public void run() {
// System.out.println("run()"); // Prints several runs
/ /}
/ /}
Copy the code

Details:

1. Cache

Results may need to wait, will block!

9. Commonly used auxiliary classes (must)

9.1, CountDownLatch

Subtraction counter: implementation calls a thread several times before firing a task

Code examples:

package com.haust.add;    

import java.util.concurrent.CountDownLatch;

/ / counter
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        // The total number is 6, the task must be executed, then use!
        CountDownLatch countDownLatch = new CountDownLatch(6);

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

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

        System.out.println("Close Door"); }}Copy the code

Principle:

countDownLatch.countDown(); / / the number 1

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

Every time a thread calls countDown() countdownlatch.await (), countdownlatch.await () will be woken up, assuming the counter goes to 0, and continue!

9.2, CyclicBarrier

Add counter: Collect 7 dragon balls to summon the divine dragon

Code examples:

package com.haust.add;

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

public class  CyclicBarrierDemo {
    public static void main(String[] args) {
        /* * Collect 7 dragon balls to summon the dragon */
        
        // Summon dragon ball thread
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
            System.out.println("Summon the Dragon successfully!");
        });

        for (int i = 1; i <=7 ; i++) {
            final int temp = i;
            // Can lambda operate on I
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()
                                   			  +"Collect"+temp+"Dragon Ball");
                try {
                    cyclicBarrier.await(); / / wait for
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch(BrokenBarrierException e) { e.printStackTrace(); } }).start(); }}}Copy the code

9.3, Semaphore

Semaphore: Semaphore

Limit traffic/grab parking space! 6 cars — 3 parking Spaces

Code examples:

package com.haust.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! Current limit! ,
        // If there are 3 threads executing (3 Spaces are full), the other threads need to wait for the 'parking space' to be released before executing!
        Semaphore semaphore = new Semaphore(3);
        
        for (int i = 1; i <=6 ; i++) {
            new Thread(()->{
                / / acquire ()
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread()
                                       		.getName()+"Grab a parking space.");
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println(Thread.currentThread()
                                       		.getName()+"Leave the parking space.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release(); / / release ()} },String.valueOf(i)).start(); }}}Copy the code

There are only three parking Spaces, and the next car can park there only when one car leaves and the space becomes vacant.

The output result is shown as follows:

Principle:

semaphore.acquire(); Get, assuming if already full, wait, wait to be released! semaphore.release(); Release, which releases the current semaphore + 1 and wakes up the waiting thread!

Function: Multiple shared resources mutually exclusive use! Concurrency limit, control the maximum number of threads!

10. ReadWriteLock

ReadWriteLock

Code examples:

package com.haust.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;

/** * Exclusive lock (write lock) can only be held by one thread at a time * Shared lock (read lock) Multiple threads can hold at the same time * ReadWriteLock * Read - Read can coexist! * Read-write cannot coexist! * Write - Write cannot coexist! * /
public class ReadWriteLockDemo {
    public static void main(String[] args) {
        //MyCache myCache = new MyCache();
        MyCacheLock myCacheLock = new MyCacheLock();

        / / write
        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 * lock */
class MyCacheLock{

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

    // When writing, only one thread is expected to write simultaneously
    public void put(String key,Object value){
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()
                               						+"Written"+key);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()
                               						+"Write" OK "to");
        } catch (Exception e) {
            e.printStackTrace();
        } finally{ readWriteLock.writeLock().unlock(); }}// Take, read, anyone can read!
    public void get(String key){
        readWriteLock.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{ readWriteLock.readLock().unlock(); }}}/** * Custom cache * unlocked */
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()
                           							+"Written"+key);
        map.put(key,value);
        System.out.println(Thread.currentThread().getName()
                           							+"Write" OK "to");
    }

    / / get 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 "OK"); }}Copy the code

The execution effect is shown as follows:

Block the queue

Blocking queue:

BlockingQueue

BlockingQueue is not new

When do we use blocking queues? : multi-threaded concurrent processing, thread pool with more!

Learn to use queues

Add, Remove

Four groups of API

way An exception is thrown Return value, no exception thrown Block waiting for Timeout waiting for
add add offer() put() offer(,)
remove remove poll() take() poll(,)
Detects the head element of the queue element peek()

Code examples:

package com.kuang.bq;

import java.util.Collection;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        test4();
    }
    /** * 1. No return value, exception method */
    public static void test1(a){
        // Queue size
        ArrayBlockingQueue blockingQueue = 
            						new ArrayBlockingQueue<>(3);

        System.out.println(blockingQueue.add("a"));// true
        System.out.println(blockingQueue.add("b"));// true
        System.out.println(blockingQueue.add("c"));// true
        
        // System.out.println(blockingQueue.add("d"));
		// IllegalStateException: Queue Full Throws an exception -- the Queue is full!
        
        System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = =");

        System.out.println(blockingQueue.element());//
        // check who the team leader element is
        
        System.out.println(blockingQueue.remove());//

        System.out.println(blockingQueue.remove());//
        System.out.println(blockingQueue.remove());//

        // System.out.println(blockingQueue.remove());
        / / Java. Util. NoSuchElementException throws an exception - the queue is empty!
    }

    /** * 2. Returns a value without throwing an exception */
    public static void test2(a){
        // 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.peek());

        // System.out.println(blockingQueue.offer("d")); 
        // false does not throw an exception!
        
        System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = =");
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        
        System.out.println(blockingQueue.poll()); 
        // null does not throw an exception!
    }

    /** * 3. Wait, block (always block) */
    public static void test3(a) throws InterruptedException {
        // Queue size
        ArrayBlockingQueue blockingQueue = 
            						new ArrayBlockingQueue<>(3);

        // block all the time
        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        // blockingQueue.put("d"); // The queue runs out of space
        
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take()); 
        // Without this element, block and wait

    }


    /** * 4. Wait, block (wait timeout) */
    public static void test4(a) throws InterruptedException {
        // Queue size
        ArrayBlockingQueue blockingQueue = 
            						new ArrayBlockingQueue<>(3);

        blockingQueue.offer("a");
        blockingQueue.offer("b");
        blockingQueue.offer("c");
        // blockingQueue.offer("d",2,TimeUnit.SECONDS); 
        // Wait more than 2 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); // Wait more than 2 seconds to exit}}Copy the code

SynchronousQueue

SynchronousQueue SynchronousQueue

There is no capacity, an element in, must wait to take out, can put another element in!

Put, take

Code examples:

package com.haust.bq;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;

SynchronousQueue: Unlike other BlockingQueues, SynchronousQueue does not store elements. A SynchronousQueue must take an element from it before it can be put in. * /
public class SynchronousQueueDemo {
    public static void main(String[] args) {
        BlockingQueue<String> blockingQueue = 
            					new SynchronousQueue<>(); // Synchronize the queue

        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()
                                   						+" put 1");
                // put enters an element
                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 {
                // Sleep 3s takes an element
                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(); }}Copy the code

The execution result is as follows:

12. Thread Pools (emphasis)

Thread pool: 3 methods, 7 parameters, 4 rejection policies

Pooling technology

The operation of the program, the essence: occupy the resources of the system! (Optimize resource usage => pooling technique)

Thread pool, connection pool, memory pool, object pool Create and destroy. A waste of resources

Pooling technology: prepare some resources in advance, and if someone wants to use them, come to me to take them and return them to me after using them.

Benefits of thread pools:

  • 1. Reduce system resource consumption
  • 2, improve the speed of response
  • 3, convenient management

Thread reuse, can control the maximum number of concurrent, management threads

Thread pools: 3 big methods

Thread pools: 3 big methods

Sample code:

package com.haust.pool;

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

public class Demo01 {
    public static void main(String[] args) {
        // Executors Tools, 3 major methods
        // Executors.newSingleThreadExecutor(); // Create a single thread pool
        // Executors.newFixedThreadPool(5); // Create a thread pool of fixed size
        // Executors.newCachedThreadPool(); // Create a scalable thread pool

        // A thread pool for a single thread
		ExecutorService threadPool = 	
            					Executors.newSingleThreadExecutor();
        
        try {
            for (int i = 1; i < 100; i++) {
                // After using thread pools, use thread pools to create threads
                threadPool.execute(()->{
                    System.out.println(
                        Thread.currentThread().getName()+" ok"); }); }}catch (Exception e) {
            e.printStackTrace();
        } finally {
            // The thread pool is used up, the program ends, close the thread poolthreadPool.shutdown(); }}}Copy the code

Thread pool: 7 parameters

Seven parameters

Source code analysis:

public static ExecutorService newSingleThreadExecutor(a) { 
    return new FinalizableDelegatedExecutorService (
        new ThreadPoolExecutor(
            1.1.0L, 
            TimeUnit.MILLISECONDS, 
            new LinkedBlockingQueue<Runnable>())); 
}

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(
        5.5.0L, 
        TimeUnit.MILLISECONDS, 
        new LinkedBlockingQueue<Runnable>()); 
}

public static ExecutorService newCachedThreadPool(a) { 
    return new ThreadPoolExecutor(
        0, 
        Integer.MAX_VALUE, 
        60L, 
        TimeUnit.SECONDS, 
        new SynchronousQueue<Runnable>()); 
}

ThreadPoolExecutor ()

public ThreadPoolExecutor(intCorePoolSize, // Core thread pool sizeintMaximumPoolSize, // Maximum core thread pool sizelongBlockingQueue<Runnable> workQueue, // Thread factory: ThreadFactory ThreadFactory // RejectedExecutionHandler Handle) { 
    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; 
}
Copy the code

Create a thread pool manually

Manually create a thread pool and customize 7 parameters for the tool Executors. Procedure

Sample code:

package com.haust.pool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

// Executors Tools, 3 major methods
// Executors.newSingleThreadExecutor(); // Create a single thread pool
// Executors.newFixedThreadPool(5); // Create a thread pool of fixed size
// Executors.newCachedThreadPool(); // Create a scalable thread pool

/** * Four rejection strategies: * * * new ThreadPoolExecutor. AbortPolicy () the bank is full, the others to come in, don't deal with this person, Throw an exception * * new ThreadPoolExecutor. CallerRunsPolicy () * which come of where to go! Such as your father let you to notify the mother to wash clothes, mother refused, let you go back to notify dad wash * * new ThreadPoolExecutor. DiscardPolicy () * queue is full, the task he lost never throw an exception. * * * new ThreadPoolExecutor. DiscardOldestPolicy () queue is full, the attempt to and the first competition, also won't throw an exception! * /
public class Demo01 {
    public static void main(String[] args) {
        // Custom thread pool! Work ThreadPoolExecutor
        ExecutorService threadPool = new ThreadPoolExecutor(
                2.// int corePoolSize, size of the core thread pool
                5.// int maximumPoolSize, the maximum size of the core thread pool
                3.// long keepAliveTime, timeout 3 seconds no one call will be released, put close window
                TimeUnit.SECONDS,// TimeUnit unit, timeout unit in seconds
                new LinkedBlockingDeque<>(3),// Block queue (maximum 3 people in waiting area)
                Executors.defaultThreadFactory(),// Default thread factory
            	// One of the four rejection strategies:
            	// When the queue is full, try to compete with the earliest one without throwing an exception!
                new ThreadPoolExecutor.DiscardOldestPolicy());  
        
        // When the queue is full, try to compete with the earliest one without throwing an exception!
        try {
            // Max load: Deque + Max
            / / than RejectedExecutionException
            for (int i = 1; i <= 9; i++) {
                // After using thread pools, use thread pools to create threads
                threadPool.execute(()->{
                    System.out.println(
                        Thread.currentThread().getName()+" ok"); }); }}catch (Exception e) {
            e.printStackTrace();
        } finally {
            // The thread pool is used up, the program ends, close the thread poolthreadPool.shutdown(); }}}Copy the code

Thread pool: four rejection policies

Four rejection strategies

/** * Four rejection strategies: * * * new ThreadPoolExecutor. AbortPolicy () the bank is full, the others to come in, don't deal with this person, Throw an exception * * new ThreadPoolExecutor. CallerRunsPolicy () * which come of where to go! Such as your father let you to notify the mother to wash clothes, mother refused, let you go back to notify dad wash * * new ThreadPoolExecutor. DiscardPolicy () * queue is full, the task he lost never throw an exception. * * * new ThreadPoolExecutor. DiscardOldestPolicy () queue is full, the attempt to and the first competition, also won't throw an exception! * /
Copy the code

Summary and expansion

How to set the maximum pool capacity!

Understand: IO intensive, CPU intensive: (tuning)

Directly on the code:

package com.haust.pool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class Demo01 {
    public static void main(String[] args) {
        // Custom thread pool! Work ThreadPoolExecutor
        
        // How to define the maximum thread
        // 1, CPU intensive, a few cores, just a few, can maintain the highest efficiency of CPU!
        // 2, IO intensive > determine your application is very IO intensive thread,
        // For example, the program has 15 large tasks.
        // Set the IO intensive parameter (maximum number of threads) to greater than 15
        
        // Get the number of CPU cores
        System.out.println(
            Runtime.getRuntime().availableProcessors());/ / 8 cores
        
        ExecutorService threadPool = new ThreadPoolExecutor(
                2.// int corePoolSize, the core thread pool size
            	// int maximumPoolSize, the maximum thread pool size for an 8-core computer is 8
                Runtime.getRuntime().availableProcessors(),
                3.// long keepAliveTime, which is released when no one calls it after 3 seconds
                TimeUnit.SECONDS,// TimeUnit unit, timeout unit in seconds
                new LinkedBlockingDeque<>(3),// Block queue (maximum 3 people in waiting area)
                Executors.defaultThreadFactory(),// Default thread factory
            	// One of the four rejection strategies:
            	// When the queue is full, try to compete with the earliest one without throwing an exception!
                new ThreadPoolExecutor.DiscardOldestPolicy());  
        
        // When the queue is full, try to compete with the earliest one without throwing an exception!
        try {
            // Max load: Deque + Max
            / / than RejectedExecutionException
            for (int i = 1; i <= 9; i++) {
                // After using thread pools, use thread pools to create threads
                threadPool.execute(()->{
                    System.out.println(
                        Thread.currentThread().getName()+" ok"); }); }}catch (Exception e) {
            e.printStackTrace();
        } finally {
            // The thread pool is used up, the program ends, close the thread poolthreadPool.shutdown(); }}}Copy the code