Concurrency Design Principles of Java Concurrency API Case Analysis

table of Contents

0, Interstitial 2020CSDN blog star voting news

1. Opening

Second, concurrency and parallelism

Three, concurrent programs bring key problems

1. Data competition

2. Deadlock

3. Livelock

4. Insufficient resources

5. Priority reversal

Four, Java Concurrency API (detailed)

1. Basic concurrency

2. Synchronization mechanism

3. Actuator

4. Fork/Join framework

5. Concurrent data structure

Five, concurrent design pattern

1. Signal model

2. Rendezvous mode

3. Mutually exclusive mode

4. Read-write lock mode

5. Thread pool mode

6. Thread local storage mode

Six, final summary


0, Interstitial 2020CSDN blog star voting news

Recently (January 11th-January 24th), the 2020CSDN blog star selection is underway. As a one-year-old Xiaobai, I was fortunate to be selected as the Top 200. First of all, I am very grateful to the CSDN official for choosing me. I thought it was just coming. Join in the fun and watch the big guys PK ^_^#.

Based on the fighting situation of the big bosses in the past 4 days, the top ten big bosses are sitting very steadily, and they have to be admired and praised! The real strength can be seen, the number of articles is not important, but the quality is more important! Everything speaks with data, as shown in the figure:

As of 2021-01-15 14:40:01

Looking at the amazing data of the big guys, there is a big gap with me. I can’t help feeling that Xiaobai only hopes to be in the Top 100. I hope that the big guys, friends, fans, and other little whites like me who see this news can top it. Let me vote unanimously for me. Let’s cheer and make progress together in the New Year, and everything goes well! ^_^#

Voting address: https://bss.csdn.net/m/topic/blog_star2020/detail?username=charzous

Or scan the code to vote:

Key point: every vote will be recorded, and it’s easy to ask Charzous for help after you cast a vote (crazy hints at canvassing votes)

From now until the 24th, you can vote every day. The more votes you have, the higher the contribution rankings. I will remember your name!

1. Opening

In many blog posts about Java network programming that I wrote before, multithreading technology has been initially used, which is a related application case of Java concurrency. Now, we need to learn some principles of concurrent programming, understand the ins and outs, and have a relatively deeper understanding of the principles of concurrent design. And I found that after learning Java network programming, with a practical understanding, and then learning its related principles, it is easier to understand the knowledge of the principles.

This article records the important knowledge I have learned, and it makes it easier to see it after sorting it out, and it is also convenient for reviewing and studying later!

Second, concurrency and parallelism

It is amazing that the two concepts of concurrency and parallelism have been studied in the course of operating systems. At that time, they were only theoretical studies at the operating system level, without involving actual application scenarios and programming languages. Now review the knowledge for further study and find that it is more practical to understand.

There are many definitions of concurrency and parallelism. Here are a few that are easy to understand:

Concurrent refers to two or more events occur within the same time interval, the multi-channel programming, means at the same time a plurality of tasks running simultaneously within the program, which is executed simultaneously on the macro, micro serial of.

Parallel means that simultaneously perform multiple tasks on a microscopic, occurs at the same point of time on. Obviously, if multiple program tasks are required to run in parallel, multiple processors are needed. In a single-processor system, there is only concurrency but no parallelism.

 Using a single core to execute multiple tasks on a single processor is concurrency , and the operating system's scheduler will quickly switch from one task to another, so it seems that all tasks are running at the same time. The simultaneous execution of multiple tasks on different processors or processor cores at the same time is parallel .

The most important thing is the principle and design of concurrency, which leads to an important concept of "synchronization" in concurrency .

Synchronization is a mechanism for coordinating two or more tasks to obtain expected results. include:

  1. Control synchronization : task dependencies. When the execution of one task needs to depend on the end of another task, the second task cannot start before the completion of the former.
  2. Data access synchronization : When two or more tasks access a shared variable, only one task can access the variable at any time.

A concept closely related to synchronization is the critical section , which is a piece of code used to ensure that only one task can access shared resources at any time. The mutual exclusion is the mechanism used to ensure this critical section.

Three, concurrent programs bring key problems

The writing and design of concurrent programs need to do a lot of work on the synchronization/mutual exclusion mechanism to ensure the correct execution of concurrent programs. Therefore, the following key issues need to be paid attention to.

1. Data competition

To put it simply, multiple tasks write to shared variables, and there is no critical section of the synchronization mechanism as a constraint, and there is data competition in the program.

public class Account{
    private float balance;
    public void modify(float difference){
        float value=this.balance;
        this.balance=value+difference;
    }
}

 For example, in the above example, if there are two tasks that execute the same Account object for the modify operation, the initial balance=1000, and the final balance should be 3000, but if the two tasks execute the first statement of the modify method at the same time, they execute the first statement at the same time. Two sentences, the result becomes 2000. Therefore, the Account class is not thread-safe and does not implement atomic operations and synchronization mechanisms.

2. Deadlock

Simply put, two or more tasks are waiting for a resource released by another thread, and this thread is also waiting for the resource released by the previous task, such a concurrent program has a deadlock.

When the following conditions are fully satisfied, a deadlock will occur.

  1. Mutually exclusive conditions : The resource in the deadlock is not sharable, and only one task can use the resource in a period of time.
  2. Request and retention conditions : The task has retained at least one resource, but a new request is made, and the resource needs to be released. At this time, the task is blocked and waiting, and the resources it has acquired will not be released.
  3. Non-deprivation conditions : Resources can only be released by the tasks that hold them.
  4. Circular waiting condition : task 1 is waiting for the resource occupied by task 2, and task 2 is waiting for the resource occupied by task 3,..., so there is a circular waiting.

The methods to deal with deadlocks are: prevention, avoidance, detection, and release. These four basic methods have specific implementation algorithms. 

3. Livelock

If there are two tasks in the system that always change their state because of the other's behavior, a livelock will occur.

For example, tasks 1 and 2 require resources 1 and 2. At this time, task 1 owns resource 1 and locks, and task 2 owns resource 2 and locks. When they can't access the required resources, they release their resources and start a new cycle, so that it continues indefinitely, and neither task will end their execution process.

4. Insufficient resources

Livelock is a situation of insufficient resources, when the task cannot obtain the required resources in the system to continue the task.

The solution is to ensure the principle of fairness .

5. Priority reversal

When a low-priority task holds the resources required by a high-priority task, priority inversion will occur, and the low-priority task will be executed in advance.

Four, Java Concurrency API (detailed)

Java contains a wealth of concurrent APIs, which can be used flexibly during concurrent programming.

1. Basic concurrency

  1. Thread class: describes all threads that execute concurrent Java applications.
  2. Runnable interface: Another way to create concurrent programs in Java.
  3. ThreadLocal class: used to store variables belonging to a thread. (Used when there is no synchronization mechanism)
  4. ThreadFactory interface: the base class that implements the Factory design pattern to create custom threads.

2. Synchronization mechanism

The concurrent synchronization mechanism of Java supports the definition of a critical section for accessing a shared resource; different tasks are synchronized on a common point.

  1. sychronized keyword : You can define a critical section in a code block or a complete method.
  2. Lock interface: Provides richer and more flexible synchronization operations. Among them, ReentantLock is used to implement a conditional association lock; ReentantRead-WriteLock separates read and write operations; StampedLock includes a mode for controlling read/write access, which is a new feature of Java 8.

The following are relatively unfamiliar:

  1. CountDownLatch class: allows multiple tasks to wait for the end of multiple operations.
  2. CyclicBarrier class: allows multiple threads to synchronize on a common point.
  3. Phaser category: Allows to control the execution of tasks that are divided into multiple phases. All tasks cannot enter the next stage before completing the sub-tasks of the current stage.

3. Actuator

  1. Executor interface and ExecutorService interface: including the common execute method.
  2. ThreadPoolExecutor class: you can define the maximum number of thread pool executor tasks.
  3. ScheduledThreadPoolExecutor class: a special type of executor that executes tasks after a delay or periodically executes tasks.
  4. Callable interface: An alternative interface to the Runnable interface that provides a return value.
  5. Future interface: Contains methods for obtaining the return value of Callable and controlling its state.

4. Fork/Join framework

The framework defines a special actuator, especially for divide-and-conquer problems, and provides an optimization mechanism with low overhead. Main classes and interfaces:

  1. ForkJoinPool: Implemented an executor for running tasks.
  2. ForkJoinTask: Tasks that can be executed in the above classes.
  3. ForkJoinWorkerThread: A thread that is ready to perform tasks in class 1.

5. Concurrent data structure

Commonly used data structures in Java such as: ArrayList, Map, HashMap, etc. cannot be used in concurrent programs, because there is no synchronization mechanism and it is not thread-safe. If the synchronization mechanism is adopted by oneself, the computational overhead of the program increases.

Therefore, Java provides special data structures in concurrent programs, which are thread-safe, and there are two main categories:

  1. Blocking data structure: Contains methods that block calling tasks, for example, when the value is obtained, the data result is empty.
  2. Non-blocking data structure: The operation can be performed immediately without blocking the calling task.

Commonly used concurrent data structures (thread safety):

  1. ConcurrentHashMap: non-blocking hash table ( other data structures starting with the keyword Concurrent )
  2. ConcurrentLinkedDeque: non-blocking list
  3. LinkedBlockQueue: Blocking queue
  4. CopyOnWriteArrayList: Read and read shared, write and write mutually exclusive, read and write mutually exclusive.
  • Implemented the List interface
  • Holds a ReentrantLock lock = new ReentrantLock();
  • The bottom layer is an array declared with volatile transient
  • Read and write separation, copy a new array when writing, and assign the new array to array after inserting, modifying or removing operations

     5. PriorityBlockingQueue: Blocking queue, sorting elements based on priority.

     6. AtomicBoolean, AtomicInteger, AtomicLong and AtomicReference: atomic realization of basic Java data types. (Atomic variables can be used instead of synchronization)

Five, concurrent design pattern

1. Signal model

The realization of this mode course adopts semaphore or mutual exclusion, ReentrantLock or Semaphore in Java, or wait and notify methods of Object class.

public void task1(){
    section1();
    commonObject.notify();
}

public void task2(){
    commonObject.wait();
    section2();
}

The section2 method is always executed after section1. 

2. Rendezvous mode

In the promotion of signal mode, the first task will wait for the completion of an activity of the second task, while the second task is also waiting for the completion of an activity of the first task. The difference is that two objects are used.

public void task1(){
    section1_1();
    commonObject1.notify();
    commonObject2.wait();
    section1_2();
}

public void task2(){
    section2_1();
    commonObject2.notify();
    commonObject1.wait();
    section2_2();
}

The sequence of statements cannot be modified, otherwise deadlock may occur.

 section2_2 is always executed after section1_1, and section1_2 is always executed after section2_1.

3. Mutually exclusive mode

The mutual exclusion mechanism is used to realize the critical section and ensure that the operations are mutually exclusive.

public void task1() {
    preSection();
    try {
        lockObject.lock();//临界段开始
        section();
    }catch (Exception e){
        ……
    }finally {
        lockObject.unlock();//临界段结束
        postSection();
    }
}

4. Read-write lock mode

This mode defines a special lock that contains two internal locks: one for read operations and one for write operations.

The characteristics of the lock: read and read sharing, write and write mutual exclusion, read and write mutual exclusion.

The ReentrantReadWriteLock class of the Java Concurrency API implements this pattern

5. Thread pool mode

This mode is widely used and reduces the overhead of creating threads for each task each time. It is composed of a thread set and a queue of tasks to be executed. The ExceutorService interface can implement this mode.

6. Thread local storage mode

The ThreadLocal class in Java implements thread-local variables, which can use thread-local storage, and each thread will access a different instance of the variable.

Six, final summary

Concurrent algorithm design follows:

1. Use thread-safe Java concurrent API

2. Use local thread variables in static classes and shared occasions

3. Avoid deadlock: sort the locks

4. Use atomic variables

 

In this article, I recorded the key knowledge of learning concurrent design principles, as well as some commonly used and important Java concurrent programming APIs. After learning theoretical knowledge, I have a deeper understanding of this part. If I can add practical projects or specific Case analysis can be considered true mastery. Therefore, I also found a more practical case for practice-file search, which will be recorded in detail in the next blog. I hope that the combination of theory and practice will further improve the understanding of knowledge!

If you think it’s good, welcome to "one-click, three-link", like, bookmark, follow, comment directly if you have any questions, and exchange and learn!


My CSDN blog: https://blog.csdn.net/Charzous/article/details/112603639

Guess you like

Origin blog.csdn.net/Charzous/article/details/112603639