Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the implementation principle of volatile?

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

This article will explain in detail what the implementation principle of volatile is, and the content of the article is of high quality, so the editor will share it for you as a reference. I hope you will have a certain understanding of the relevant knowledge after reading this article.

The Java programming language allows threads to access shared variables, and to ensure that shared variables are updated accurately and consistently, threads should ensure that the variable is obtained separately through exclusive locks.

This may be a bit of a round. let's look at a piece of code first:

Public class VolatileTest implements Runnable {private boolean flag = false; @ Override public void run () {while (! flag) {} System.out.println ("thread ends running...");} public void setFlag (boolean flag) {this.flag = flag;} public static void main (String [] args) throws InterruptedException {VolatileTest v = new VolatileTest () Thread T1 = new Thread (v); t1.start (); Thread.sleep (2000); v.setFlag (true);}}

The running result of this code:

You can see that although the v.setFlag (false) method is called in the code, the thread does not end running. This is because in the above code, there are actually two threads running, one is the main thread, and the other is the T1 thread created in the main thread. So we can see that variables in the thread are invisible to each other. To understand the visibility of variables in threads, we need to understand Java's memory model.

Java memory model

In Java, all instance fields, static variables, and array elements are stored in heap memory, and the heap memory is shared between threads. Local variables, method definition parameters, and exception number parameters are stored on the Java virtual machine stack. Java virtual machine stacks are thread-private so they are not shared between threads, they have no memory visibility issues, and they are not affected by the memory model.

The Java memory model (Java Memory Model referred to as JMM) determines when a thread's write to a shared variable is visible to other threads. JMM defines an abstract relationship between threads and main memory:

Shared variables between threads are stored in main memory, each thread has a private local memory, and a copy of the thread shared variable is stored in the local memory. Local memory is an abstract probability of JMM and does not really exist. It covers caching, write buffers, registers, and other hardware and compilation optimizations.

The abstract concept diagram of the Java memory model is as follows:

After looking at the concept of the Java memory model, let's take a look at how main memory interacts with thread-local memory in the memory model.

Interaction between main memory and local memory

The interaction between main memory and local memory is the implementation of how a variable is copied from the main memory to the local memory and how to write back to the main memory from the local memory. The Java memory model provides 8 operations to complete the interaction between the main memory and the local memory. They are as follows:

Lock: a variable that acts on main memory that identifies a variable as the exclusive state of a thread.

Unlock: a variable acting on main memory that releases a variable in a locked state so that the released variable can be locked by other threads.

Read (read): a variable acting on main memory that transfers a variable from main memory to the thread's local memory for use by subsequent load actions.

Load (load): a variable that acts on local memory and places the value of the variable from the main memory of the read operation into a copy of the variable in local memory.

Use: a variable acting on local memory that passes the value of a variable in local memory to the execution engine, which is performed whenever the virtual machine encounters a bytecode instruction that needs to use the value of the variable.

Assign: a variable that acts on local memory that assigns a variable received from the execution engine to a variable in local memory, which is performed whenever the virtual machine encounters a bytecode instruction that assigns a value to the variable.

Store: a variable that acts on local memory and passes the value of the variable in local memory to main memory for later write operations to use.

Write (write): a variable that acts on main memory and puts the value of the variable obtained by the store operation from local memory into the variable of main memory.

From the above eight operations, we can see that when a variable is copied from the main memory to the thread's local memory, the read and load operations need to be performed sequentially, and when a variable is synchronized from the local memory to the main memory, the store and write operations need to be performed sequentially. The Java memory model only requires that the above two sets of operations be performed sequentially, but not continuously. For example, when accessing variables an and b in main memory, the order in which they may appear is read a read b load b load a. In addition, the Java memory model states that the following rules must be met when performing the above eight basic operations:

Read and load,store and write operations are not allowed to occur alone, and these two sets of operations must be in pairs.

A thread is not allowed to discard its most recent assign operation. That is, variables must be synchronized to main memory after they are changed in the thread's local memory.

A thread is not allowed to synchronize data from the thread's local memory to the main memory for no reason.

An uninitialized variable is not allowed in the thread's local memory.

A variable allows only one thread to perform lock operations on it at a time, but a thread can perform multiple lock operations on a variable. When a thread performs multiple lock operations on the same variable, it needs the same number of unlock operations to release the variable.

If a variable performs a lock operation, the copy of the variable in local memory is cleared, and the read and load operations need to be re-performed when the variable is needed.

If a variable does not perform a lock operation, then the unlock operation cannot be performed on that variable, nor is it allowed to unlock a variable that has been lock operated by other threads. That is to say, lock and unlock operations occur in pairs and in the same thread.

Before you can unlock a variable, you must synchronize the value of that variable into main memory.

Semantic visibility of volatile memory

After we have a rough understanding of Java's memory model, we can see why this is so when we look at the code above. First of all, the value of flag in the main memory is false, and when the T1 thread executes, the operations executed in turn are read, load, and use. At this time, the value of flag in the local memory of the T1 thread is also false, and the thread will execute all the time. When the main thread calls the v.setFlag (true) method, the falg in the main thread is assigned to true, because the assign operation is used, so the value of local memory in the main thread is synchronized to main memory, and the value of flag in main memory is true. However, the T1 thread does not perform read and load operations again, so the value of flag in the T1 thread is still false, so the T1 thread does not terminate the run. To stop the T1 thread correctly, you just need to prefix the flag variable with the volatile modifier, because volatile guarantees the visibility of the variable. Since volatile is consistent across threads, can volatile ensure security in concurrency situations? The answer is no, because volatile cannot guarantee the atomicity of variables. Examples are as follows:

Public class VolatileTest2 implements Runnable {private volatile int i = 0; @ Override public void run () {for (int juni0witj)

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report