Java learning notes - JUC concurrent programming

Posted by millwardt on Sat, 08 Jan 2022 08:55:29 +0100

Concurrent programming

1. Processes and threads

Process: an execution process of a program. It is the basic unit for the system to run the program.

A thread is similar to a process, but a thread is a smaller execution unit than a process. A process can produce multiple threads during its execution. Different from the process, multiple threads of the same kind share the heap and method area resources of the process, but each thread has its own program counter, virtual machine stack and local method stack. Therefore, when the system generates a thread or switches between threads, the burden is much smaller than that of the process. For this reason, threads are also called lightweight processes.

Java has no permission to start threads and operate hardware, but it can call native methods, which call the underlying c + + code

Concurrency and parallelism

Concurrency refers to the simultaneous occurrence of multiple events in the same time period. Multiple tasks seize resources from each other.

Parallelism means that multiple things happen at the same time. Multiple tasks do not seize resources from each other.

Several states of threads

  • NEW freshmen
  • RUNNABLE run
  • BLOCKED
  • WAITING waiting
  • TIMED_WAITING timeout
  • TERMINATED

The difference between wait/sleep

1. From different classes

wait comes from the Object class

sleep comes from the Thread class

2. About lock release

wait releases the lock, sleep does not

3. Different scope of use

wait must be used in synchronous code blocks

sleep anywhere

4. Need to catch exceptions

wait does not need to catch exceptions

sleep must catch exceptions

2. The difference between Synchronized and Lock

1. Synchronized built-in Java keyword, Lock is a Java class

2. Synchronized cannot judge the status of obtaining the Lock, but Lock can judge

3. Synchronized will automatically release the lock. Lock must be manually locked and manually released! Deadlock may be encountered

4. Synchronized thread 1 (get lock - > block), thread 2 (wait); Lock does not have to wait all the time. Lock will have a trylock to try to obtain the lock, which will not cause a long wait.

5. Synchronized is a reentrant lock, non interruptible and unfair; Lock, which is reentrant, can judge the lock, and can set its own fair lock and unfair lock;

6. Synchronized is suitable for locking a small number of code synchronization problems, and Lock is suitable for locking a large number of synchronization codes;

3. False Awakening

When a condition is met, many threads are awakened, but only some of them are useful awakenings, and the others are useless

Example: producers and consumers what we want to achieve is that producers create one and consumers consume one. There are four threads in total, two for production and two for consumption

public class A {
    public static void main(String[] args) {
        Data data = new Data();

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

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

class Data{
    private int num = 0;

    public synchronized void incream() throws InterruptedException {
        //Note this if
        if (num != 0){
            this.wait();
        }
        num++;
        System.out.println(Thread.currentThread().getName() + "  =>  " + num);
        this.notifyAll();
    }

    public synchronized void decream() throws InterruptedException {
        //Note this if
        if (num == 0){
            this.wait();
        }
        num--;
        System.out.println(Thread.currentThread().getName() + "  =>  " + num);
        this.notifyAll();
    }
}

The operation results are as follows: obviously, it is not what we want, and a false wake-up occurs at this time

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-xGtkvmRO-1641626450881)(D:\Docs \ document \ notes \ interview \ img \ false wake-up. png)]

The solution is to change if to while to prevent false wake-up

Conclusion: if it is judged by if, the thread will start running from the code after the wait after wake-up, but will not re judge the if condition. It will directly continue to run the code after the if code block. If while is used, it will also run from the code after the wait, but the loop condition will be re judged after wake-up. If it is not true, execute the code block after the while code block, If established, continue to wait.

This is why we use while instead of if, because after the thread is awakened, the execution starts after wait

The above uses the synchronized keyword to synchronize threads

It can also be implemented using lock, and it can wake up the specified thread instead of all. example:

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{
    private int num = 1;
    Lock lock = new ReentrantLock();
    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();


    public void printA() {
        lock.lock();
        try {
            while (num != 1){
                condition1.await();
            }
            num = 2;
            System.out.println(Thread.currentThread().getName() + "=> AAAAA");
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printB() {
        lock.lock();
        try {
            while (num != 2){
                condition2.await();
            }
            num = 3;
            System.out.println(Thread.currentThread().getName() + "=> BBBBB");
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printC() {
        lock.lock();
        try {
            while (num != 3){
                condition3.await();
            }
            num = 1;
            System.out.println(Thread.currentThread().getName() + "=> CCCCC");
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
A Wake up after thread execution B thread 
B Wake up after thread execution C thread 
C Wake up after thread execution A thread 

4. Collection unsafe

4.1. Unsafe

ArrayList is not safe in the case of concurrency, and Java. Net may appear in add in the case of multithreading util. Concurrent modificationexception concurrent modification exception.

There are three ways to implement thread safe lists:

  • List<String> list = new Vector<>();
  • List<String> list = Collections.synchronizedList(new ArrayList<>());
  • List<String> list = new CopyOnWriteArrayList<>();

CopyOnWriteArrayList: copy on write! An optimization strategy in the field of COW computer programming

The core idea is that if multiple Callers require the same resource (such as memory or data storage on disk) at the same time, they will jointly obtain the same pointer to the same resource. The system will not really copy a private copy to the caller until a caller tries to modify the resource content, The original resources seen by other Callers remain unchanged. This process is transparent to other Callers. The main advantage of this method is that if the caller does not modify the resource, no private copy will be created. Therefore, multiple Callers can share the same resource only during the read operation.

There is no need to lock when reading. If multiple threads are adding data to the CopyOnWriteArrayList when reading, the old data will still be read, because the old CopyOnWriteArrayList will not be locked when writing.

When multiple threads call, list, read, fixed, write (overwrite operation exists); Avoid overwriting when writing, resulting in data disorder;

The add source code is as follows:

Add a Lock lock when writing, then copy an original array, create a new array 1 longer than the original array, then write new elements, and replace the original old array with the new array. setArray is actually a process of replacing the old array with a new array.

private transient volatile Object[] array;

public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}

final void setArray(Object[] a) {
    array = a;
}

4.2. Unsafe

Like List, it is thread unsafe

There are two kinds of thread safe sets:

  • Set class wrapped with synchronized of Collections tool class
  • Write replicated JUC solutions using CopyOnWriteArraySet

The add of CopyOnWriteArraySet is similar to the add of CopyOnWriteArrayList. The bottom layer uses CopyOnWriteArrayList. When adding, the indexOf function will be used to judge whether the same element exists in the original array, and then a snapshot of the original array will be kept to prevent the insertion of duplicate elements in the case of multithreading. Here is the source code:

private final CopyOnWriteArrayList<E> al;

public boolean add(E e) {
    return al.addIfAbsent(e);
}

//The addIfAbsent method is a method of the CopyOnWriteArrayList class

//Check for duplicate elements and keep a snapshot before adding
public boolean addIfAbsent(E e) {
    Object[] snapshot = getArray();
    return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
    addIfAbsent(e, snapshot);
}

//After the lock lock is added, the current array will be obtained again,
//If the current array is different from the previously reserved snapshot, it will check whether there are the same elements in the array as the element e to be added. If there are no same elements, continue to add element e
//If the current array is the same as the previously reserved snapshot, add the element to be added
//When adding a new element, a new array of len+1 will be created, the group of the original array will be copied, e will be added, and then the original array will be overwritten.
private boolean addIfAbsent(E e, Object[] snapshot) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] current = getArray();
        int len = current.length;
        if (snapshot != current) {
            // Optimize for lost race to another addXXX operation
            int common = Math.min(snapshot.length, len);
            for (int i = 0; i < common; i++)
                if (current[i] != snapshot[i] && eq(e, current[i]))
                    return false;
            if (indexOf(e, current, common, len) >= 0)
                return false;
        }
        Object[] newElements = Arrays.copyOf(current, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}

4.3. Unsafe Map

The same HashMap basic class also has concurrent modification exceptions,

resolvent:

  • Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
  • Map<String, String> map = new ConcurrentHashMap<>();

5,Callable

Callable differs from threads created by inheriting Thread and implementing Runnable interface:

1. Can have return value;
2. Exceptions can be thrown;
3. Different methods, run()/call()

Here are three ways to implement multithreading: inherit the Thread class, implement the Runnable interface, implement the Callable interface, and use the implementation class FutureTask of the Runnable interface as a bridge.

public class CallableTest {
    public static void main(String[] args) throws Exception {
        //Inherit Thread class
        new A().start();

        //Lambda expressions that implement Runnable interfaces
        new Thread(() -> System.out.println("Runnable Run...")).start();

        //Callable interface. The constructor of Thread class can only receive Runnable interface. If you want to use callable interface to start a Thread
        //A Runnable implementation class is needed as a bridge This class is FutureTask
        //Differences between Callable interface and Runnable interface: 1 Can have return value; 2. Exceptions can be thrown 3 Different methods
        FutureTask<String> futureTask = new FutureTask<String>(() -> {
            System.out.println("Callable Run...");
            return "Callable Test";
        });
        new Thread(futureTask).start();
        //Print the return value of the Callable call method
        //The get method may block
        System.out.println(futureTask.get());
    }
}

class A extends Thread {
    @Override
    public void run() {
        System.out.println("Thread Run...");
    }
}

6. Common auxiliary classes of JUC

6.1,CountDownLatch

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        // The total is 6
        CountDownLatch countDownLatch = new CountDownLatch(6);

        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "==> Go Out");
                countDownLatch.countDown(); // Number of threads per thread - 1
            },String.valueOf(i)).start();
        }
        countDownLatch.await(); // Wait for the counter to zero and execute down
        System.out.println("close door");
    }
}

Main methods:

  • countDown minus one;
  • await waits for the counter to return to zero

await waits for the counter to return to zero, wakes up, and then continues to run down

6.2,CyclickBarrier

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-X6zCGArf-1641626450885)(D:\Docs \ document \ notes \ interview \ img\CyclickBarrier.png)]

7 is the set number of threads. When the number of threads increases to 7, the last thread entering will execute this behavior.

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        // Main thread
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7,() -> {
            System.out.println("Summon the Dragon");
        });

        for (int i = 1; i <= 7; i++) {
            // Child thread
            int finalI = i;
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "Collected the third" + finalI + "Dragon Ball");
                try {
                    cyclicBarrier.await(); // Add count wait
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

6.3,Semaphore

public class SemaphoreDemo {
    public static void main(String[] args) {

        // Number of threads, parking space, current limiting
        Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i <= 6; i++) {
            new Thread(() -> {
                // acquire() gets
                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 (Exception e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release(); // Release
                }
            }).start();
        }
    }
}
Thread-1 Grab a parking space
Thread-0 Grab a parking space
Thread-2 Grab a parking space
Thread-0 Leave the parking space
Thread-2 Leave the parking space
Thread-1 Leave the parking space
Thread-5 Grab a parking space
Thread-3 Grab a parking space
Thread-4 Grab a parking space
Thread-5 Leave the parking space
Thread-3 Leave the parking space
Thread-6 Grab a parking space
Thread-4 Leave the parking space
Thread-6 Leave the parking space

Process finished with exit code 0

Principle:

semaphore.acquire() gets the resource. If the resource has been used up, wait for the resource to be released before using it!

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

Function: mutually exclusive use of multiple shared resources! Concurrent flow restriction, control the maximum number of threads!

7. Read write lock

If we do not lock, multithreaded reading and writing will cause the problem of unreliable data.

We can also use synchronized heavy lock and light lock to ensure the reliability of data.

But this time we use more fine-grained locks: ReadWriteLock and readlock read-write locks to ensure. The lock is exclusive when writing, and other threads are not allowed to read and write when writing; The read lock is a shared lock. Other threads can read but cannot write when reading.

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

        for (int i = 0; i < 6; i++) {
            int temp = i;
            new Thread(() -> {
                myCache.set(String.valueOf(temp), String.valueOf(temp));
            }, String.valueOf(i)).start();
        }

        for (int i = 0; i < 6; i++) {
            int temp = i;
            new Thread(() -> {
                myCache.get(String.valueOf(temp));
            }, String.valueOf(i)).start();
        }
    }
}

//Without locking, the thread is unsafe and will be cut off when reading and writing data
class MyCache{
    private volatile Map<String, String> map = new HashMap<>();

    public void set(String key, String value){
        System.out.println(Thread.currentThread().getName() + " write in " + key);
        map.put(key, value);
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " write in ok...");
    }

    public void get(String key){
        System.out.println(Thread.currentThread().getName() + " read " + key);
        map.get(key);
        System.out.println(Thread.currentThread().getName() + " read ok...");
    }
}

//Fine grained read-write lock, exclusive when writing and shared when reading
class MyCacheLock{
    private volatile Map<String, String> map = new HashMap<>();
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    public void set(String key, String value){
        lock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + " write in " + key);
            map.put(key, value);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " write in ok...");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.writeLock().unlock();
        }
    }

    public void get(String key){
        lock.readLock().lock();

        try {
            System.out.println(Thread.currentThread().getName() + " read " + key);
            map.get(key);
            System.out.println(Thread.currentThread().getName() + " read ok...");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.readLock().unlock();
        }
    }
}

8. Blocking queue

8.1,BlockQueue

Is a subclass of Collection

Usage scenarios: multithreaded concurrent processing and thread pool

BlockingQueue has four sets of APIs

modeThrow exceptionNo exception will be thrown and there is a return valueBlocking, waitingTimeout wait
add toaddofferputoffer(timenum.timeUnit)
Removeremovepolltakepoll(timenum,timeUnit)
Judge team leader elementelementpeek--

Examples are as follows:

public class BlockingQueueDemo {
    private ArrayBlockingQueue queue = new ArrayBlockingQueue(3);

    //Throwing anomaly
    @Test
    public void test1() {
        queue.add("a");
        queue.add("b");
        queue.add("c");

//        queue.add("d");  //Queue full

        System.out.println(queue.element());

        System.out.println(queue.remove());
        System.out.println(queue.remove());
        System.out.println(queue.remove());

//        System.out.println(queue.remove()); //NoSuchElementException

//        System.out.println(queue.element());  //NoSuchElementException
    }

    //Return value, no exception thrown
    @Test
    public void test2() {
        queue.offer("a");
        queue.offer("b");
        queue.offer("c");

        System.out.println("offer: " + queue.offer("d")); //false

        System.out.println("peek: " + queue.peek());

        System.out.println("poll: " + queue.poll());
        System.out.println("poll: " + queue.poll());
        System.out.println("poll: " + queue.poll());

        System.out.println("poll: " + queue.poll()); // null
    }

    //Blocking waiting waiting
    @Test
    public void test3() throws InterruptedException {
        queue.put("a");
        queue.put("b");
        queue.put("c");

//        queue.put("d");  // Keep waiting

        System.out.println(queue.take());
        System.out.println(queue.take());
        System.out.println(queue.take());
        System.out.println(queue.take());  //Keep waiting
    }

    //If the timeout exceeds the set time, it will not wait any longer
    @Test
    public void test4() throws InterruptedException {
        queue.offer("a", 2, TimeUnit.SECONDS);
        queue.offer("b", 2, TimeUnit.SECONDS);
        queue.offer("c", 2, TimeUnit.SECONDS);
        System.out.println("Timeout insertion...");
        //2 seconds or unable to insert, return false, and then proceed to the next step
        System.out.println(queue.offer("d", 2, TimeUnit.SECONDS));

        System.out.println(queue.poll(2, TimeUnit.SECONDS));
        System.out.println(queue.poll(2, TimeUnit.SECONDS));
        System.out.println(queue.poll(2, TimeUnit.SECONDS));
        System.out.println(queue.poll(2, TimeUnit.SECONDS)); //Leave after 2 seconds and return null
    }
}

8.2. Synchronization queue

If the synchronization queue has no capacity, it can also be regarded as a blocking queue with capacity of 1;

When you enter an element, you must wait for it to be taken out before you can put another element in it;

put method and take method;

Unlike other blockingqueues, Synchronized does not store elements;

If you put an element, you must take it out first, otherwise you can't put in the value!

And the take of SynchronousQueue uses lock lock to ensure thread safety.

public class SynchronousQueueDemo {
    public static void main(String[] args) {
        SynchronousQueue<String> queue = new SynchronousQueue<>();

        new Thread(() -> {
            try {
                queue.put("a");
                System.out.println(Thread.currentThread().getName() + " put a");
                TimeUnit.SECONDS.sleep(1);
                queue.put("b");
                System.out.println(Thread.currentThread().getName() + " put b");
                TimeUnit.SECONDS.sleep(1);
                queue.put("c");
                System.out.println(Thread.currentThread().getName() + " put c");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T1").start();

        new Thread(() -> {
            try {
                String s1 = queue.take();
                System.out.println(Thread.currentThread().getName() + " take " + s1);
                String s2 = queue.take();
                System.out.println(Thread.currentThread().getName() + " take " + s2);
                String s3 = queue.take();
                System.out.println(Thread.currentThread().getName() + " take " + s3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "T2").start();
    }
}
T1 put a
T2 take a
T1 put b
T2 take b
T1 put c
T2 take c

9. Thread pool (key)

Thread pool: three methods, seven parameters and four rejection strategies

Pool technology

The operation of the program, essence: occupy the resources of the system! We need to optimize the use of resources = = > pooling technology

Thread pool, JDBC connection pool, memory pool, object pool, etc....

The creation and destruction of resources are very resource consuming

Pooling Technology: prepare some resources in advance. If someone wants to use them, come to me and return them to me after use, so as to improve efficiency.

9.1. Benefits of thread pool:

1. Reduce resource consumption;

2. Improve response speed;

3. Convenient management;

Thread reuse, maximum concurrent number can be controlled and threads can be managed;

9.2 thread pool: three methods

  • ExecutorService threadPool = Executors.newSingleThreadExecutor();// Single thread
  • ExecutorService threadPool2 = Executors.newFixedThreadPool(5); // Create a fixed thread pool size
  • ExecutorService threadPool3 = Executors.newCachedThreadPool(); // Scalable

9.3 seven parameters

public ThreadPoolExecutor(int corePoolSize,  //Core thread pool size
                          int maximumPoolSize, //Maximum thread pool size
                          long keepAliveTime,  //If no one calls it, it will be released
                          TimeUnit unit, //Timeout unit
                          BlockingQueue<Runnable> workQueue, //Blocking queue
                          ThreadFactory threadFactory, //Thread factories generally do not need to move when creating threads
                          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.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-kn4rfQHq-1641626450888)(D:\Docs \ document \ notes \ interview \ img \ thread pool creation specification png)]

Alibaba's Java operation manual clearly states that for integer MAX_ The initial value of value is large, so generally, we use the underlying ThreadPoolExecutor to create a thread pool.

9.4 rejection strategy

1. AbortPolicy() / /: the rejection policy is: if the bank is full and someone else comes in, don't deal with this person's and throw an exception. If the maximum load is exceeded, an exception will be thrown: queue capacity size + maxPoolSize

2. CallerRunsPolicy() / /: the rejection policy is: the thread pool will be executed by which thread is called wherever it comes from

3. new ThreadPoolExecutor.DiscardPolicy(): / / the rejection policy is: if the queue is full, throw the exception, and no exception will be thrown.

4. new ThreadPoolExecutor.DiscardOldestPolicy() / /: the rejection policy is: if the queue is full, try to compete with the earliest process without throwing exceptions

9.5. How to set the size of thread pool

1. CPU intensive: the number of cores of a computer can be selected according to the number of cores; Select the size of the maximunPoolSize

2. I/O intensive:

There are 15 large tasks in the program, which io takes up a lot of resources; I/O intensive is to judge the number of I/O consuming threads in our program, which is about twice to twice the maximum number of I/O.

10. Four functional interfaces

Functional interface: an interface with only one method

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-Xuug89Br-1641626450889)(D:\Docs \ document \ notes \ interview \ img \ four functional interfaces. png)]

  • Function < R, t > function interface has input and output. R apply(T t); R and T are generic
  • Predict < T > definite interface has input and output Boolean test (T); The input is a user-defined input, and the output is a Boolean value of the judgment result
  • Supplier < T > the supply interface only has output T get();
  • Consumer < T > the consumer interface can only enter void accept (T);

11. ForkJoin

ForkJoin is in jdk1 7. Execute tasks in parallel! Improve efficiency ~. In large amounts of data, the speed will be faster!

In big data: MapReduce core idea - > split big tasks into small tasks!

11.1. ForkJoin features: work theft!

The implementation principle is: double ended queue! You can get the task from above and below for execution!

11.2. How to use ForkJoin?

  • 1. Execute through ForkJoinPool

  • 2. Compute task execute (forkjointask <? > task)

  • 3. The calculation class should inherit ForkJoinTask;

    Calculation class of ForkJoin

public class ForkJoinDemo extends RecursiveTask<Long> {
    private Long start;
    private Long end;

    private Long temp = 10000L; //critical value

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

    @Override
    protected Long compute() {
        if ((end - start) < temp){
            Long sum = 0L;
            for (Long i = start; i <= end; ++i) {
                sum += i;
            }
            return sum;
        } else {
            Long middle = start + (end - start) / 2;
            ForkJoinDemo task1 = new ForkJoinDemo(start, middle);
            task1.fork();
            ForkJoinDemo task2 = new ForkJoinDemo(middle + 1, end);
            task2.fork();
            return task1.join() + task2.join();
        }
    }
}

use

@Test
public void test02() throws ExecutionException, InterruptedException {
    long start = System.currentTimeMillis();

    ForkJoinPool forkJoinPool = new ForkJoinPool();
    ForkJoinTask<Long> forkJoinDemo = new ForkJoinDemo(0L, 10_0000_0000L);
    ForkJoinTask<Long> submit = forkJoinPool.submit(forkJoinDemo);
    Long sum = submit.get();
    long end = System.currentTimeMillis();
    System.out.println("sum: " + sum + "time consuming: " + (end - start));
}

Parallel stream computing, very fast

@Test
public void test03(){
    long start = System.currentTimeMillis();

    Long sum = LongStream.rangeClosed(0L, 10_0000_0000L).parallel().reduce(0, Long::sum);
    long end = System.currentTimeMillis();
    System.out.println("sum: " + sum + "time consuming: " + (end - start));
}

12. Asynchronous callback

The original intention of Future design: modeling the result of an event in the Future!

Similar to Ajax

But we usually use completable future

12.1. runAsync asynchronous callback without return value

public static void main(String[] args) throws ExecutionException, InterruptedException 
{
        // Initiate a request

        System.out.println(System.currentTimeMillis());
        System.out.println("---------------------");
        CompletableFuture<Void> future = CompletableFuture.runAsync(()->{
            //Initiate an asynchronous task
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+".....");
        });
        System.out.println(System.currentTimeMillis());
        System.out.println("------------------------------");
        //Output execution results
        System.out.println(future.get());  //Get execution results
 }

12.2. Asynchronous callback supplyAsync with return value

//Asynchronous callback with return value
CompletableFuture<Integer> completableFuture=CompletableFuture.supplyAsync(()->{
    System.out.println(Thread.currentThread().getName());
    try {
        TimeUnit.SECONDS.sleep(2);
        int i=1/0;
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return 1024;
});

//A consumer functional interface is passed into whenComplete. This method will be executed whether it succeeds or fails
//The first parameter is the return value of successful execution, and the second is the error message of failed execution
//exceptionally is equivalent to the callback function with exception. If an exception occurs, the code in it will be executed, which is somewhat similar to the catch in try catch
//Except that what is passed in exceptionally is a functional interface When an exception occurs, the obtained value is the return value of this block
System.out.println(completableFuture.whenComplete((t, u) -> {
    //success callback
    System.out.println("t=>" + t); //Normal return result
    System.out.println("u=>" + u); //Error message for throwing exception
}).exceptionally((e) -> {
    //error callback
    System.out.println(e.getMessage());
    return 404;
}).get());

whenComplete: there are two parameters, one is t and the other is u

T: Is the result of the normal return of the representative;

U: Is the error message that represents the exception thrown;

If an exception occurs, get can get the value returned by exceptionally;

Topics: Java Back-end JUC