JUC foundation, it's enough to read this article

JUC Foundation

1. Tube side: monitor, monitor, lock

It ensures that only one process is active in the pipe at the same time, that is, the operations defined in the pipe are called by only one process at the same time (implemented by the compiler) However, this does not guarantee that the processes are executed in the designed order

Synchronization in the JVM is based on entering and exiting (locking and unlocking) monitor objects. Each object will have a monitor object, which will be created and destroyed together with java objects

2. A java file can only have one public, and other classes can be omitted

3. Multi thread programming steps

one ⃣ Common resource classes: create attributes and operation methods in resource classes
 two ⃣ Judge, work and notify in the resource class
 three ⃣ Create multiple threads and call the operation methods of the resource class
 four ⃣ ⅸ preventing false wake-up problems (key points)
Prevent false wake-up: 1 Put the relevant judgment conditions into the while loop to avoid false wake-up of methods such as wait (when a thread enters the wait for the first time, it will wait, but if it executes the wait method for the second time during the wait, it will be false wake-up. Continue to execute the subsequent code, and add while to solve it)
​
At the same time, the relevant unlocking needs to be added to the finally code block to avoid problems

4. Solutions to unsafe ArrayList, HashSet and HashMap threads:

//Vector resolution
List<String> list=new Vector<>();
​
//Collections
List<String> list=Collections.synchronizedList(new ArrayList<>());
​
//CopyOnWriteArrayList solution
List<String> list=new CopyOnWriteArrayList<>();
​
//CopyOnWriteArraySet resolution
List<String> list=new CopyOnWriteArraySet<>();
​
//ConcurrentHashMap solution
List<String> list=new ConcurrentHashMap<>();

synchronized object locks depend on whether the objects are the same. If so, whoever gets the lock first will execute the contents first. However, it should be noted that the static modification method is not used. If modified, no matter how many objects are created, they all represent class objects, that is, whoever gets the lock first will execute first

synchronized is the foundation of synchronization: every object in Java can be used as a lock.
It is embodied in the following three forms.
For normal synchronization methods, the lock is the current instance object.
For static synchronization methods, the lock is the Class object of the current Class.
For synchronized method blocks, locks are objects configured in synchronized parentheses

1. Lock

1⃣️

Unfair lock: threads starve to death, high efficiency
​
Fair lock: the sun shines and the efficiency is relatively low

2⃣️

Reentrant lock:
Both synchronized (implicit) and Lock (explicit) are reentrant locks
 Recursive lock

3⃣️

Deadlock (handwritten deadlock code):
1. Insufficient system resources
 2. The process running sequence is inappropriate
 3. Improper allocation of resources
​
terminal: use jps-1 + stack tracing tool: jstack + process number

2.Callable

Four ways to create threads

1. Inherit Thread class

2. Implement Runnable interface

3.Callable interface

4. Thread pool mode

/* Runnable Difference between Callable interface and Callable interface:
 1.Runnable no return value
 2.Runnable The interface does not throw an exception
 3.The names of the implementation methods are different. The former is the run method and the latter is the call method
 4.Callable The interface cannot create a thread by means of new Thread. FutureTask (implementation class of flexible interface) can be used to construct and pass Callable */
​
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
​
//Compare two interfaces
//Implement Runnable interface
class MyThread1 implements Runnable {
    @Override
    public void run() {
​
    }
}
​
//Implement Callable interface
class MyThread2 implements Callable {
​
    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+" come in callable");
        return 200;
    }
}
​
public class Demo1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //The Runnable interface creates a thread
        new Thread(new MyThread1(),"AA").start();
​
        //**Callable interface, error**
       // new Thread(new MyThread2(),"BB").start();
​
        //FutureTask
        FutureTask<Integer> futureTask1 = new FutureTask<>(new MyThread2());
​
        //lam expression
        FutureTask<Integer> futureTask2 = new FutureTask<>(()->{
            System.out.println(Thread.currentThread().getName()+" come in callable");
            return 1024;
        });
      
        //Create a thread
        new Thread(futureTask2,"lucy").start();
        new Thread(futureTask1,"mary").start();
​
//        while(!futureTask2.isDone()) {
//            System.out.println("wait.....");
//        }
        //Call the get method of FutureTask
        System.out.println(futureTask2.get());
​
        System.out.println(futureTask1.get());
​
        System.out.println(Thread.currentThread().getName()+" come over");
        //FutureTask principle future task: it can be understood as the idea of asynchronous io and mapreduce
        /**
         * 1,The teacher was thirsty in class. It was inappropriate to buy a ticket. The lecture thread continued.
         *   Just open the thread, find the monitor of the class to buy water for me, buy the water back, and get it directly when necessary
         *
         * 2,4 Students, 1 student, 1 + 2 5, 2 students 10 + 11 + 12 50, 3 students 60 + 61 + 62, 4 students 100 + 200
         *      The second student has a large amount of calculation,
         *     FutureTask Start a single thread to calculate for 2 students, summarize 1, 3 and 4 first, and finally wait for 2 students to complete the calculation, and summarize uniformly
         *
         * 3,Test, do what you can do, and finally look at what you can't do
         *
         * Summary once
         *
         */
​
    }
}

3.JUC powerful auxiliary class

1. Reduce the count countDownLatch, including two methods: countDown and await. The former decreases by 1 every time, and the latter waits. When the initial value of the thread is reduced to 0, the operation after await is executed, just like locking the door. When everyone in the classroom is gone, lock the door

import java.util.concurrent.CountDownLatch;
​
//Demonstrate CountDownLatch
public class CountDownLatchDemo {
    //After six students left the classroom one after another, the monitor locked the door
    public static void main(String[] args) throws InterruptedException {
​
        //Create a CountDownLatch object and set the initial value
        CountDownLatch countDownLatch = new CountDownLatch(6);
​
        //After six students left the classroom one after another
        for (int i = 1; i <=6; i++) {
            //This method doesn't work. It won't lock the door until the end
            new Thread(()->{
                System.out.println(Thread.currentThread().getName()+" Classmate No. left the classroom");
​
                //Count - 1
                countDownLatch.countDown();
​
            },String.valueOf(i)).start();
        }
​
        //wait for
        countDownLatch.await();
​
        System.out.println(Thread.currentThread().getName()+" lock the door");
    }
}

2. The circular barrier, such as gathering seven dragon balls to summon the dragon, will execute await only after gathering, which is a bit like the flink distributed snapshot

        CyclicBarrier cyclicBarrier =
                new CyclicBarrier(NUMBER,()->{
                    System.out.println("*****Collect 7 dragon balls to summon the dragon");
                });
​
        //Process of gathering seven dragon balls
        for (int i = 1; i <=7; i++) {
            new Thread(()->{
                try {
                    System.out.println(Thread.currentThread().getName()+" The star dragon was collected");
                    //wait for
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start(); //The thread name is valueof
        }

3. Semaphore, acquire and release the license. For example, several parking spaces can only be entered by other cars after the car has gone

4. Read write lock

1. Optimistic lock: it does not support concurrent operations and is inefficient

2. Pessimistic lock: supports concurrency,

3. Table lock: even if only one row is modified, the whole table will be locked

4. Row lock: deadlock will occur when the row is locked

5. Read lock: shared lock (many locks can be read together) and deadlock occurs

6. Write lock: exclusive lock (the next one can only be written after writing one), and deadlock occurs

/*Cause of read lock Deadlock: for example, thread 1 reads from a table and modifies it at the same time. It needs to wait for thread 2 to read before modifying it. In this way, thread 2 will wait for deadlock
 Cause of write lock Deadlock: threads 1 and 2 write to two records at the same time, and they will wait for each other to deadlock
​
The evolution of read-write locks;
Multiple read threads can be read together, but there cannot be read and write threads at the same time, that is, read and write are mutually exclusive (the doctrine is that you can't write when reading, but you can read when writing), and read sharing (ReentrantReadWriteLock)
Disadvantages of read-write lock:
It causes lock hunger, reading all the time and no writing operation (reading and writing are mutually exclusive). For example, many people get on the subway and it is difficult to get off
​
Degradation of read / write lock:
Demote a write lock to a read lock. A read lock cannot be upgraded to a write lock
 jdk8 Description: first obtain the write lock, then obtain the read lock, release the write lock, and release the read lock (the write permission is higher than the read permission)*/
​
import java.util.concurrent.locks.ReentrantReadWriteLock;
​
//Demote read / write lock
public class Demo1 {
​
    public static void main(String[] args) {
        //Reentrant read-write lock object
        ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
        ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();//Read lock
        ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();//Write lock
​
        //Lock degradation
        //2 acquire read lock
        readLock.lock();
        System.out.println("---read");
​
        //1 get write lock
        writeLock.lock();
        System.out.println("mile");
​
        //3 release the write lock
        //writeLock.unlock();
​
        //4 release the read lock
        //readLock.unlock();
    }
}

 

5. Blocking queue

Add: the queue is first in first out (like remove in the figure below, the poll follows this principle), and the stack is first in first out

Definition: when the queue is empty or full, elements cannot be obtained and added, and will be blocked (Note: it is assumed that the code will be blocked if the addition is full, but if there is a remove code below, it will continue to be executed instead of stuck in the addition line, and if there is no remove, it will also be blocked). It is fully automated and does not need to be processed manually

Classification:

1. Arrayblockingqueue (commonly used), a bounded blocking queue composed of an array structure

2. Linkedblockingqueue (commonly used), a bounded (but the default size is integer.MAX_VALUE) blocking queue composed of linked list structure

3.DelayQueue, a delay unbounded blocking queue implemented using priority queue

4.PriorityBlockingQueue, an unbounded blocking queue that supports priority sorting

5. Synchronous queue, which does not store the blocking queue of elements, that is, the queue of a single element

6.LinkedTransferQueue, an unbounded blocking queue composed of linked lists

7.LinkedBlockingDeque, a bidirectional blocking queue composed of linked lists

6. Thread pool

1)newCachedThreadPool
 Create a cacheable thread pool. If the length of the thread pool exceeds the processing needs, you can flexibly recycle idle threads. If there is no recyclable thread, you can create a new thread. This type of thread pool is characterized by:
There is almost no limit on the number of worker threads created (in fact, there is also a limit, the number is Interger. MAX_VALUE), so you can flexibly add threads to the thread pool.
If the task is not submitted to the thread pool for a long time, that is, if the worker thread is idle for the specified time (the default is 1 minute), the worker thread will terminate automatically. After termination, if you submit a new task, the thread pool recreates a worker thread.
When using CachedThreadPool, you must pay attention to controlling the number of tasks. Otherwise, the system will be paralyzed because a large number of threads run at the same time.
2)newFixedThreadPool
 Create a thread pool with a specified number of worker threads. Each time a task is submitted, a worker thread is created. If the number of worker threads reaches the initial maximum number of thread pool, the submitted task is stored in the pool queue. FixedThreadPool is a typical and excellent thread pool. It has the advantages of improving program efficiency and saving the overhead when creating threads. However, when the thread pool is idle, that is, when there are no runnable tasks in the thread pool, it will not release the working threads and occupy certain system resources.
3)newSingleThreadExecutor
 Create a single thread Executor, that is, only create a unique worker thread to execute tasks. It will only use a unique worker thread to execute tasks to ensure that all tasks are executed in the specified order (FIFO, LIFO, priority). If this thread ends abnormally, another thread will replace it to ensure sequential execution. The biggest feature of a single working thread is that it can ensure the sequential execution of various tasks, and no more than one thread will be active at any given time.
4)newScheduleThreadPool
 Create a thread pool with a fixed length, and support timed and periodic task execution, as well as timed and periodic task execution. Execution is delayed by 3 seconds.

1. Thread pool is for background programs, which is to improve memory and cpu efficiency, similar to optimization on the client. Connection pool is database connection oriented. It is used to optimize database connection resources, similar to that on the client

2. The thread pool in Java is implemented through the Executor framework, which uses Executor, Executors, ExecutorService and ThreadPoolExecutor

 

3. The bottom layers of several thread pools call ThreadPoolExecutor, which has seven parameters

4. Seven parameters

• Int corePoolSize the number of core threads in the thread pool
 • Int maximumPoolSize is the maximum number of threads that can be accommodated
 • long keepAliveTime idle thread lifetime
 • TimeUnit unit
 • BlockingQueue < runnable > workqueue holds the queue submitted but not executed
 • ThreadFactory threadFactory creates a factory class for threads
 • RejectedExecutionHandler handler the rejection policy when the waiting queue is full

5. Workflow and work strategy: 3, 4 and 5 will wait for 1 and 2 of the corePool in the blocking queue. When 6, 7 and 8 come again, a new thread will be started (equivalent to queue jumping), that is, when the resident thread pool and blocking queue are full, a new thread pool will be opened for processing (according to the rejection Policy)

 

 

 

6. Customize thread pool

 

import java.util.concurrent.*;
​
//Custom thread pool creation
public class ThreadPoolDemo2 {
    public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                2L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );
​
        //10 customer requests
        try {
            for (int i = 1; i <=10; i++) {
                //implement
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" Handle the business");
                });
            }
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            //close
            threadPool.shutdown();
        }
    }
}

7. Fork/Join framework

1.Fork: split a complex task and make it small. Join: merge the results of the split task (similar to mapreduce). The bottom layer of fork is implemented recursively through recursive task

import java.util.concurrent.*;
​
class MyTask extends RecursiveTask<Integer> {
​
    //The split difference cannot exceed 10, and the calculation is within 10
    private static final Integer VALUE = 10;
    private int begin ;//Split start value
    private int end;//Split end value
    private int result ; //Return results
​
    //Create a structure with parameters
    public MyTask(int begin,int end) {
        this.begin = begin;
        this.end = end;
    }
​
    //Split and merge process
    @Override
    protected Integer compute() {
        //Judge whether the added two values are greater than 10
        if((end-begin)<=VALUE) {
            //Addition operation
            for (int i = begin; i <=end; i++) {
                result = result+i;
            }
        } else {//Further split
            //Get intermediate value
            int middle = (begin+end)/2;
            //Split left
            MyTask task01 = new MyTask(begin,middle);
            //Split right
            MyTask task02 = new MyTask(middle+1,end);
            //Call method split
            task01.fork();
            task02.fork();
            //Consolidated results
            result = task01.join()+task02.join();
        }
        return result;
    }
}
​
public class ForkJoinDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //Create MyTask object
        MyTask myTask = new MyTask(0,100);
        //Create branch merge pool object
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(myTask);
        //Get the results after the final merge
        Integer result = forkJoinTask.get();
        System.out.println(result);
        //Close pool object
        forkJoinPool.shutdown();
    }
}

2. Completable future asynchronous callback (you can see it from the idea view)

 

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
​
//Asynchronous and synchronous calls
public class CompletableFutureDemo {
    public static void main(String[] args) throws Exception {
        //Synchronous call
        CompletableFuture<Void> completableFuture1 = CompletableFuture.runAsync(()->{
            System.out.println(Thread.currentThread().getName()+" : CompletableFuture1");
        });
       //End method
        completableFuture1.get();
​
        //mq message queue
        //Asynchronous call
        CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(()->{
            System.out.println(Thread.currentThread().getName()+" : CompletableFuture2");
            //Simulation anomaly
            int i = 10/0;
            return 1024;
        });
        completableFuture2.whenComplete((t,u)->{
            System.out.println("------t="+t);
            System.out.println("------u="+u);
        }).get();
​
    }
}

8. Spin lock

Keep trying until you succeed, CAS

Mutex features:
Lock the shared resource before accessing it, and unlock it after accessing it. After locking, any other thread trying to lock again will be blocked until the current thread is unlocked. If more than one thread is blocked during unlocking, all threads on the lock will be programmed into the ready state. The first thread that becomes ready will perform the lock operation, and other threads will enter the waiting state. In this way, only one thread can access the resources protected by the mutex. (only one thread can have a mutex at a time, and other threads can only wait)
​
Spin lock is a special kind of mutually exclusive lock. When resources are locked, other threads want to lock again. At this time, the thread will not be blocked to sleep, but will fall into a circular waiting state (the CPU can't do other things). Loop check whether the resource holder has released resources. The advantage of this is to reduce the resource consumption of the thread from sleep to wake up, But it will always occupy CPU resources. It is applicable to the situation that the lock of the resource is held for a short time and you do not want to spend too much resources on the wake-up of the thread.

9. Deflection lock

In the absence of actual competition, it can continue to optimize for some scenarios. If not only there is no actual competition, but there is only one thread using locks from beginning to end, maintaining lightweight locks is a waste. The goal of biased locking is to reduce the performance consumption caused by using lightweight locks when there is no competition and only one thread uses locks. Lightweight locks require CAS at least once every time they apply for and release locks, but biased locks require CAS only once during initialization.

"Bias" means that the bias lock assumes that only the first thread applying for the lock will use the lock in the future (no thread will apply for the lock again). Therefore, it is only necessary to record the owner in CAS in Mark Word (it is also updated in essence, but the initial value is empty). If the record is successful, the bias lock is obtained successfully and the record lock status is bias lock, In the future, if the current thread is equal to the owner, the lock can be obtained directly at zero cost; Otherwise, it indicates that other threads compete and expand into lightweight locks.

Spin lock optimization cannot be used for biased locking, because once another thread applies for a lock, the assumption of biased locking is broken.

shortcoming

Similarly, if it is obvious that other threads apply for locks, biased locks will quickly expand into lightweight locks.

But the side effect is much smaller.

If necessary, use the parameter - XX:-UseBiasedLocking to disable bias lock optimization (on by default).

Keywords: Java Big Data Back-end Concurrent Programming JUC

Added by jonniejoejonson on Sun, 09 Jan 2022 06:49:02 +0200