CAS has many advantages, such as avoiding mutex and improving the running efficiency of programs. However, CAS also has very obvious disadvantages. Therefore, when using CAS, we should take its advantages and disadvantages into account and select the technology rationally.

Let’s look at some of the major drawbacks of CAS.

ABA problem

First of all, the biggest disadvantage of CAS is the ABA problem.

The criterion for deciding whether CAS should carry out swap is “whether the current value is consistent with the expected value”. If so, it is considered that the value has not changed during this period, which is ok in most cases.

But in some business scenarios, we want to know for sure if the value has changed since the last time we saw it. For example, if this value goes from A to B, and then from B back to A, not only do we think it has changed, we think it has changed twice.

In this scenario, when we use CAS, we don’t see the two changes, because it’s not enough to say “is the current value consistent with the expected value?” CAS check did not value, but to compare the current value and expected value is equal to, if the value of A variable into A new value from the old values A B again, back to the old value, due to the initial value A and now the value of A is equal, so the CAS will think the value of A variable during this period there have been no changes. Therefore, CAS cannot detect whether a value has been changed during this time, it can only check that the value that appears is the same as the original value.

Let’s take an example: suppose the first thread gets an initial value of 100, and then performs a calculation. In the process of calculation, a second thread changes the initial value to 200, and then a third thread changes 200 back to 100. Wait until the first thread is evaluated to CAS, it will compare the current value is equal to the start to the initial value of 100, will find indeed at this time is equal to 100, so a thread is considered during this time value has not been modified, will of course change this 100 into just calculated the new value, but in fact, This value has been modified by other threads in the process, which can cause ABA problems.

If an ABA problem occurs, thread one has no way of knowing if another thread has changed the value during the calculation. Since the first thread finds that the value is equal to the expected value, it will assume that no thread has changed the value of the variable in the meantime, so some of its subsequent operations logic, Is according to this value during this period has not been modified “logic to deal with, such as it may be possible to print log:” this modification is smooth “, but it should trigger other logic, such as when it was found during this period has modified the value, other threads should print is actually “the modification process by interference”.

To solve

So how to solve this problem? Add a version number. If we add A version number to the value itself, then the path of the value changes from A→B→A to 1A→2B→3A. In this way, we can compare the version number to determine whether the value has changed, which is more reliable than if we directly compare the two values. So through this idea can solve the ABA problem.

The AtomicStampedReference class is provided in the atomic package, which is specifically designed to solve ABA problems using version numbers, An AtomicStampedReference maintains a data structure like
, where the int is a count (version number), and the atom updates both the Object and the int version number, thus solving the ABA problem. Because we’re trying to determine whether it’s been modified, not by whether the value has changed, but by whether the version number has changed, even if the value is the same, the version number is different.,int>

This is an introduction to the first shortcoming of CAS, ABA.

Spin time is too long

The second disadvantage of CAS is that the spin time is too long.

Because the CAS cannot be successfully executed at a single time, the CAS is implemented in conjunction with a loop. Sometimes, the CAS is executed in an infinite loop. The CAS can be successfully modified until the thread contention is not fierce.

However, if our application scenario is inherently highly concurrent, it is possible that the CAS operation will never be successful, and the loop time will become longer and longer. During this time, CPU resources are consumed all the time, which can have a significant impact on performance. Therefore, we are required to choose whether to use CAS according to the actual situation. In high concurrency scenarios, CAS is usually inefficient.

The scope cannot be flexibly controlled

A third disadvantage of CAS is that there is no flexibility in controlling the scope of thread-safety.

Usually, we perform CAS on a single shared variable, not multiple shared variables. This variable can be an Integer, a Long, an object type, etc. However, we cannot perform CAS on multiple shared variables simultaneously because they are independent of each other. Simply putting together atomic operations is not atomic. So if we want to do CAS on multiple objects at the same time and want to be thread-safe, it can be difficult.

One solution is to use a new class to integrate the group of shared variables, and then use the AtomicReference in the atomic package to CAS the new object as a whole. This keeps the thread safe.

By contrast, adjusting the scope of thread-safety can be very easy if we use other thread-safety techniques, such as the synchronized keyword, and if we want to lock more code, we can simply put more code into the synchronized block.

conclusion

To conclude, three disadvantages of CAS were introduced: ABA problems, long spin times and inflexible control of thread-safe ranges. We understand its shortcomings, in the selection of technology can be targeted.