This is the 7th day of my participation in the August Text Challenge.More challenges in August

directory

One, foreword

Volatile: Volatile

1. Visibility of volatile

2. The principle of volatile

Use of Volatile by Disruptor

1. Visibility of sequence

2. The wit of sequence

How does ReentrantLock ensure thread visibility

Five, the convention


One, foreword

Earlier in this series, we examined the performance of Disruptor in terms of False Sharing and lock-free implementation. Today we’ll take a look at how Disruptor achieves high performance from the perspective of using the Volatile keyword.

The volatile keyword in Java should be well known. I think many students would say that it is not difficult to use the volatile keyword in front of the field variable to ensure that the variable is visible. Or one might go further and say that volatile only guarantees visibility, not atomicity. Of course I have to say that everyone is right, but I’m going to go out on a limb and say, “You probably don’t use volatile.” Don’t believe it? Then please take a look at the following questions:

  1. What about the visibility of volatile?
  2. What is the underlying implementation of Volatile?
  3. Volatile and happen-before?

Ha, ha, ha, ha, ha, ha. ! If you’re confused, please sit back and read the rest of this article. If you are completely unmasked, you can say that you have mastered the principle and use of the volatile keyword.

Volatile: Volatile

1. Visibility of volatile

Let’s start with a bit of classic code (see below). If the Writer thread executes the Writer method first, then the Read thread executes the Reader method. So what is x? Zero or 42 or not sure? If you have a simple answer and are able to explain why, then you should be familiar with volatile. If you’re not entirely sure, keep reading.

You should know that volatile ensures visibility of variables. What about the visibility of volatile? As many students would say, the visibility of volatile is that A variable that is volatile has been modified in thread A, and then thread B reads it, so that thread A can read its newly modified value without losing the latest value due to CPU caches. That’s not wrong, but it’s not quite right either. Because he only describes half the visibility of volatile.

So let’s go back to the problem listed in the code above. I can tell you right now that x is definitely 42. Why is that? Because volatile visibility should properly be called thread visibility. Take the example in the code. All variables visible to the writer thread (such as x=42) are visible to the reader thread after v is read by the writer thread. If the reader reads v, it must be able to read x=42. Here is the official technical explanation.

2. The principle of volatile

So why is the Voaltile variable thread visible? The JMM’s write-read for volatile is coincidental before. All scenarios that comply with the Happen-before principle ensure thread visibility. With the exception of volatile, interpretation and locking are the better-known happening-before ones.

In the concrete implementation of Volatile, the JMM ensures thread visibility through its abstract memory barrier. There are four types of memory barriers in the JMM. Volatile mainly uses StoreStore and StoreLoad.

The memory barrier in the JMM is just an abstraction of the memory barrier for each processor, so that we don’t have to worry about differences and implementations between processors. If you’re interested, you can check it out. Under x86, the Lock prefix instruction (a barrier under x86) + bus Lock + cache row Lock is used to ensure the visibility of volatile.

Use of Volatile by Disruptor

1. Visibility of sequence

In Disruptor, the largest concurrent access and access conflict is the producer and consumer sequence. This sequence was also mentioned earlier when we introduced False Sharing. Disruptor specifically uses byte padding to improve its concurrency. Also to ensure that this sequence is visible in real time between producers and consumers. Therefore, volatile identifies the value field within the Disruptor.

2. The wit of sequence

Most of The Times we use volatile fields, we do simple assignments and reads. Everyone agrees that this is much faster than locking read and write. There are faster ways to make volatile volatile. UNSAFE. PutOrderedLong to assign to a volatile variable. It ensures order, but not immediate visibility. However, it can provide better performance than directly assigning to volatile. Because it does not require visibility, it does not involve immediate flushing of the cache row to main memory or L1 or L2j level cache invalidation of other cache rows that read the variable. Therefore, when using volatile, we can consider using volatile variables for situations where orderliness is required but visibility is not. Unsafe. PutOrderedXXX

Four, How does ReentrantLock ensure thread visibility

We mentioned above that releasing locks and locking comply with the happen-before principle, which ensures thread visibility. Do you know how ReentrantLock ensures thread visibility? I’ll leave that to you to explore.

Five, the convention

If you have any questions or comments about this article, please add an official account to discuss it. (Add an official account to get 10GB video and graphic materials on “Java Advanced Architecture”.)