1

There are three levels of concurrent programming, namely: security issues, activity issues, and performance issues. If you pass all three levels, you will master the high-level skill of concurrent programming.

Today, we have come to the second hurdle: to solve the problem of activity.

Liveness issues

so-called liveness problem means that the program cannot be executed.

For example, the company has a transfer business, and you have achieved thread safety, solved the security problem, and no matter how high the concurrency is, there will be no mistakes. Isn't that all right?

Of course not, the program will also have activity problems, including: deadlock, starvation, livelock.

Among them, livelock is the least difficult problem, and it is very easy to solve. Moreover, even if you don't solve it, the livelock is likely to be automatically unlocked, so don't worry about it at all. Of course, if you are interested in , you can read this article: 160c6f072efed4 Java concurrent programming-livelock: it is the kind of rare and not dangerous Bug , not much to say here, we have to catch Focus.

Deadlock and starvation are the key to the active problem , as long as there is a way to solve these two problems, the second level can be cleared.

Deadlock

deadlock means that when two or more threads are executing, they are waiting for each other due to competition for resources, thus entering a "permanent" blocked state. This sounds a bit awkward, let's look at the code directly:

class Account {
    // 余额
    private Integer balance;

    // 转账
    void transfer(Account target, Integer amt) {
        synchronized (this) {
            synchronized (target) {
                if (this.balance > amt) {
                    this.balance -= amt;
                    target.balance += amt;
                }
            }
        }
    }
}

The above is a transfer code. Assuming that there are two transactions at the same time, account A is transferred to account B, and account B is transferred to account A. There are thread one and thread two. Then, the problem is coming. Thread 1 locks account A, and thread 2 locks account B. Both of them need the resources of the other party to execute, but the resources have been locked and can only be released after the program is executed.

In this way, thread one and thread two can only wait and never execute. This is the classic deadlock problem, you can see the following picture:

死锁的资源分布

In this picture, the two threads form a perfect closed loop and cannot get out at all. You can read this article: Java concurrent programming-deadlock (on) , which describes the process of deadlock generation from beginning to end.

In that case, how can the deadlock problem be solved? no way to solve the deadlock except restarting the application. The only feasible way is to avoid the deadlock and prevent the deadlock from appearing. As for how to evade, you can read this article: Java concurrent programming-deadlock (below) , there are ideas to avoid deadlock.

hunger

starvation means that the thread cannot get the resources it needs and cannot execute it all the time. For example, the following code:

class Account {
    // 余额
    private Integer balance;

    // 转账
    void transfer(Account target, Integer amt) {
        synchronized (Account.class) {
            // 本系统操作:修改余额,花费 0.01 秒
            if (this.balance > amt) {
                this.balance -= amt;
                target.balance += amt;
            }
            // 调用外部系统:转账,花费 5 秒
            payService.transfer(this, target, amt);
        }
    }
}

This is a transfer code. If we want to perform the transfer, we must lock Account.class . However, Account.class is only one 060c6f072f00b1 created by the Java Virtual Machine. This means that all transfer transactions are serial and can only be processed one by one, which is extremely inefficient.

In addition, payService.transfer(this, target, amt) is really a waste of time. No matter how well the computer is configured, the speed cannot be improved at all.

The most fatal thing is that the completion time can't be determined. synchronized is an unfair lock. The processing sequence is random. The transaction with a short waiting time may be processed first, and the transaction with a long waiting time will not be processed.

As a result, once the business volume is large, the company's complaint calls are likely to be blown up. However, fortunately, although the transfer is very slow, there is no problem with the program itself, but there are too few resources to run.

So, how to solve the hunger problem?

You can read this article: Java concurrent programming-hunger , which talked about three ideas to alleviate hunger.

Write at the end

Concurrent programming has 3 levels: security issues, liveness issues, and performance issues. What we are going through today is the second level: liveness issues.

Starting from this level, we must pay special attention: deadlock, hunger. You can review these articles: Java concurrent programming-deadlock (top) , Java concurrent programming-deadlock (bottom) , Java concurrent programming-starvation .


JerryWu
73 声望292 粉丝