High concurrency - A concurrent programming must pay attention to the three core issues

Straight to the point

High is not easy to write concurrent programs, we need a lot of attention to the problem of high concurrency environments. To sum up these problems can be summed up in three aspects, namely security issues, activity and performance issues . Next, we will discuss in-depth around these three core issues in concurrent programming.

Security Issues

problem analysis

We in the actual work process, you may often hear this description: you write this method is not thread-safe, this class is not thread-safe! And we in the " high concurrency - The source of the problem in concurrent programming strange ," a paper, a detailed description of the source of strange problems in concurrent programming, which is caused visibility problems caching, thread switching problem caused by atoms and compiler optimization bring order issues.

Since writing concurrent programs may appear these three questions, then we are not required to check all of the programs it, look at these three issues if they exist?

In fact, we do not need to analyze whether there are three questions to all of the code, you only need to share data and program data sharing will change (that is, multiple threads simultaneously read and write the same data) were analyzed for the presence of it.

In other words, if we do not share data or data state does not change, we can ensure that the thread is safe. In fact, there are many such programs are implemented. For example: Thread Local Storage (Thread Local Storage, TLS), the same mode.

In practice, data is often shared, and the state data changes occur. For example, when we write concurrent programs, often make multiple threads simultaneously access the same data, but at least there is a thread on this data write operation. At this point, if we do not take protective measures, it is easy to cause a problem complicated by the Bug, in concurrent programming, for which there is a professional term called data race . For example, multiple threads simultaneously call the following method, the data will be competitive situation occurs.

public class ThreadTest{
    private long count = 0;
    public void incrementCount(){
        count++;
    }
}

Since the above procedure is not thread-safe, we are not just locked it can solve concurrency problems? In the end is not it so?

Next, we carried out the transformation of the above procedures, increasing the use of synchronized setCount a modified () method and a modified using synchronized getCount () method, incrementCount () method by setCount () method and getCount () method to access the count FIG variables, as follows.

public class ThreadTest{
    private long count = 0;
    public synchronized void setCount(long count){
        this.count = count;
    }
    public synchronized long getCount(){
        return this.count;
    }
    public void incrementCount(){
        set(getCount()++);
    }
}

For the modified code, access to shared variables count all places, have increased the mutex, this time, the program does not exist in the data competition, it is clear incrementCount () method is not thread-safe.

Suppose count = 0, when two threads concurrently executed getCount () method, getCount () method returns the same value 0, two threads execute getCount () ++ operation, the result is 1, then two thread 1 then the result is written to memory. 2 would have a desired value, and the result is 1.

The official name for this phenomenon is called the result of data race conditions, it refers to the order of execution depends on the thread of execution. In incrementCount ThreadTest class () method, if two threads simultaneously executed completely, the result is 1. If two threads in the order, the result is 2. In concurrent programming, the order of execution threads are not sure at this time if the program there is a race condition issue, it means that the result of program execution is uncertain which there is a huge a Bug! ! !

We described earlier for the transfer operation, if not controlled, there will be race conditions. The following example transfers class.

public class TansferAccount{
    private Integer balance;
    public void transfer(TansferAccount target, Integer transferMoney){
        if(this.balance >= transferMoney){
            this.balance -= transferMoney;
            target.balance += transferMoney;
        }
    }
}

A balance is assumed that the account 200, thread A and thread B 200 while the transfer from the account A, if two threads to simultaneously execute the following line of code,

if(this.balance >= transferMoney){

A two thread finds the account balance is greater than or equal to the amount transferred out, condition is satisfied, and then perform the transfer operation, in this case, only the balance of account A 200, it is possible to turn out 400 outwardly. This is a problem caused by a race condition.

We can understand this race condition scenario in concurrent, execution of the program is dependent on a state variable, the following pseudocode.

if(状态变量 满足 执行条件){
    执行相应的操作
}

Found a thread state variable execution condition is satisfied, began to perform the operation; if this thread when performing an operation, other threads simultaneously modify the state variables, this time, the state variables do not satisfy the conditions for execution. Sometimes, this condition is not explicitly performed, e.g., ThreadTest class incrementCount () method set (getCount () ++) operation, an implicit dependency on the getCount () result data.

problem solved

Now that the data competition and competitive conditions will lead to so many problems, how do we ensure the security thread of it? In fact, these two types of problems in the final analysis are mutually exclusive, we can use a mutex to solve these problems. About using a mutex, you can refer to [topic] high concurrency in the previous article.

Active issues

problem analysis

Active issues, is worth an operation can not be performed anymore. Typical scenarios include: deadlock, livelock and starvation.

Deadlock

A deadlock between the threads waiting for each performance, has been blocked.

Livelock

Although sometimes blocked thread did not happen, but there will be cases do not go, this is called livelock. For example, thread A and thread B while A competition for resources, found not to grab resources A, give up to seize the resource A, the same time went to snatch resource B, B can not find resource grab, while competition for resources went to A, so repeatedly, resulting in a live lock.

hunger

Thread due to inability to access the required resources can not continue to perform, this is called hunger. If there is a significant priority issues between threads, then under the CPU is busy, lower priority thread gets the opportunity to perform on very small, then thread starvation can occur; time for a thread of execution if the lock is held over long, it can lead to hunger.

problem solved

Deadlock

If a deadlock occurs happens, the general need to restart the application to address, so we must try to avoid deadlock problems.

When the deadlock occurs, the four necessary conditions for deadlock must exist, we destroy any of the conditions to avoid deadlock details, see " high concurrency - The deadlock how to do? "Article.

Livelock

Unlock Livelock problem is to let the thread random wait a short time, while the probability of such competition for other resources is much smaller. This solution livelocks way, the typical scenario is the Raft distributed consensus algorithm.

hunger

Solve the problem of hunger in general, there are three options, it can be shown as follows.

  • Provide sufficient system resources.
  • Avoid long-running thread holding the lock.
  • Equitable distribution of resources.

Here, in fact, often, we are unable to provide adequate resources for the implementation of the system thread, there is no way to determine the length of time the thread execution. Therefore, we can try to thread a fair distribution of resources, can be used to lock a fair distribution of resources for the threads fair. Fair locks In essence, to ensure that the waiting thread is sequential, front row in the waiting queue thread priority access to system resources.

Performance issues

Lock improper use, there will be a performance problem. If you use excessive lock in a program, the program will lead to a range of serial execution is too large, seriously affecting the performance of the program.

So, if we need to address performance issues, it is necessary to minimize the serial program, we can use Amdahl's Law to represent the upgrade after parallel computing processor performance.

Amdahl's Law

The Law is: the system uses a component execute faster manner, the degree of improvement of system performance that can be obtained, this implementation depends on the frequency being used, or the proportion of the total execution time.

Amdahl's Law actually defines taken to enhance (acceleration) a part of the processing functions of the measures available to improve the performance or execution time speedup.

Parallel Processing System Amdahl had committed. For a fixed load conditions, the parallel processing described acceleration effect than s, Amdahl intensively studied gives the following equation:

S=1/(1-a+a/n)

Wherein, a is the proportion of parallel computing section, n is the number of parallel processing nodes.

Thus, when a 1-a = 0 when (i.e., no serial, parallel only), the maximum speedup s = n; if a = 0 (i.e. only serial, not parallel), the minimum speedup s = 1; when when n → ∞ limit speedup s → 1 / (1-a), which is the upper limit of the ratio of the acceleration.

For example, if 25% of the entire code is a serial code, the overall performance of the parallel processing can not exceed 4. This formula has been accepted by academia, and is called "Amdahl's Law", also known as "Amdahl Theorem" (Amdahl law).

problem solved

Since the use of locks can cause performance problems, then the best solution is to use lock-free algorithms and data structures. For example, thread local storage (Thread Local Storage, TLS), copy on write (Copy-on-write), and so optimistic locking; atoms class java.util.concurrent package is a non-lock of the data structure, further, You can also use the Disruptor lock-free queue memory, a good performance.

We can also minimize the time lock held. The nature of mutex is to serialize parallel program, if you want to increase the parallelism of all, we must reduce the thread that holds the lock time. For example, we can use the read-write lock, no lock read, exclusive write. In addition, Java ConcurrentHashMap before 8 uses segmented lock technology, we can learn to achieve under the ConcurrentHashMap.

In general, the following three important indicators to assess the performance of the system:

  • Throughput: number of requests that can be processed per unit time, the higher the throughput the better the performance;
  • Delay: the time from the issue request response is received, the delay, the better the performance;
  • Concurrency: at the same time the number of requests processed. The greater the amount of concurrent general, the greater the delay, so-called delay is usually based on the amount of concurrency. For example, when the concurrency is 2000, the delay is 100 milliseconds.

to sum up

When we write concurrent programs must be concerned about the safety of the program, activity and performance issues.

  • We need to pay attention to the safety aspects of data race conditions and competition;

  • We need to pay attention to in terms of active deadlocks, live locks and hunger;

  • Performance We need to select the appropriate data structures and algorithms depending on the particular scenario.

Released 1338 original articles · won praise 2086 · Views 5.24 million +

Guess you like

Origin blog.csdn.net/l1028386804/article/details/104785113