Java Theory and Practice: using volatile variables correctly

Source: Internet
Author: User
Tags variables thread visibility volatile

The volatile variable in the Java language can be viewed as a "lighter synchronized", and the volatile variable requires less coding and less run-time overhead than the synchronized block, but the functionality it can achieve is only Part of the synchronized. This article describes several patterns that effectively use volatile variables and emphasizes several scenarios that are not suitable for use with volatile variables.

Locks provide two main features: mutexes (mutual exclusion) and visibility (visibility). Mutual exclusion allows only one thread to hold a particular lock at a time, so you can use this attribute to implement a coordinated access protocol to shared data so that only one thread at a time can use the shared data. Visibility is a little more complicated, it must ensure that the changes made to the shared data before the lock is released are visible to another thread that subsequently obtains the lock-if there is no such visibility guaranteed by the synchronization mechanism, the shared variable that the thread sees may be the value before the modification or inconsistent, which can cause many serious problems.

Volatile variable

Volatile variables have synchronized visibility properties, but do not have atomic properties. This means that the thread can automatically discover the most recent value of the volatile variable. The Volatile variable can be used to provide thread safety, but can only be applied to a very limited set of use cases: there is no constraint between multiple variables or between the current value of a variable and the modified value. Therefore, using volatile alone is not enough to implement a counter, a mutex, or any class that has a invariant (invariants) associated with multiple variables (for example, "Start <=end").

For simplicity or scalability reasons, you might prefer to use volatile variables instead of locks. When using volatile variables rather than locks, some idioms (idiom) are easier to encode and read. In addition, the volatile variable does not cause a thread to block like a lock, so it rarely causes scalability problems. In some cases, if the read operation is much larger than the write operation, the volatile variable can provide a performance advantage over the lock.

Conditions for proper use of volatile variables

You can use volatile variables instead of locks in a limited number of situations. For the volatile variable to provide ideal thread safety, the following two conditions must be met:

Write operations on variables are not dependent on the current value.

The variable is not included in the invariant with other variables.

In fact, these conditions indicate that these valid values that can be written to the volatile variable are independent of the state of any program, including the current state of the variable.

The first condition restricts the volatile variable from being used as a thread-safe counter. Although an incremental operation (x + +) looks like a separate operation, it is actually a combination of read-modify-write sequences, which must be executed atomically, and volatile cannot provide the necessary atomic attributes. Implementing the correct operation requires that the value of X remain unchanged during the operation, while the volatile variable does not achieve this. (However, if you adjust the value to write only from a single thread, you can ignore the first condition.) )

Most programming scenarios conflict with one of these two conditions, making volatile variables not universally applicable to thread safety as synchronized. Listing 1 shows a value range class that is not thread safe. It contains an invariant-the lower bound is always less than or equal to the upper bound.

Listing 1. Non-thread-safe numeric range classes

@NotThreadSafe
public class NumberRange {
private int lower, upper;
public int getLower() { return lower; }
public int getUpper() { return upper; }
public void setLower(int value) {
if (value > upper)
throw new IllegalArgumentException(...);
lower = value;
}
public void setUpper(int value) {
if (value < lower)
throw new IllegalArgumentException(...);
upper = value;
}
}

This approach restricts the state variables of the scope, so defining the lower and upper fields as volatile types does not fully implement the thread safety of the class, and thus still requires synchronization. Otherwise, if it happens that two threads execute Setlower and setupper at the same time using inconsistent values, the scope is in an inconsistent state. For example, if the initial state is (0, 5, at the same time, thread A calls Setlower (4) and thread B calls Setupper (3), it is obvious that these two operations are not eligible for the cross deposit, then two threads will be used to protect the invariant type of check, so that the final range value is (4 , 3)--An invalid value. As for the other operations on the scope, we need to make setlower () and Setupper () operations atomized-and it's not possible to define fields as volatile types.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.