Java concurrency Programming (ii) visibility of objects

Source: Internet
Author: User

The key issue in writing the correct concurrency program is that it requires proper management when accessing the mutable state of the share .

In the first section, we describe how to share and publish objects so that they can be safely accessed by multiple threads simultaneously , by synchronizing to avoid multiple threads accessing the same data at the same time. These two parts form an important basis for building thread-safe classes and building concurrent applications through the Java.util.concurrent class library.

We already know that synchronous code blocks and synchronous methods ensure that operations are performed atomically, but a common misconception is that the keyword synchronized can only be used to implement atomicity or to determine "critical areas". In fact, there is another important aspect of synchronization: Memory Visibility (Visibility). Not only do we want to prevent a thread from using the object while another object is modifying the state of the object, but we want to make sure that when a thread modifies the state of the object, other threads can see the change. If there is no synchronization, this situation is not possible. You can ensure that objects are published securely by displaying synchronization or synchronization built into the class library. In summary, the Sync keyword ensures that atomic access + memory is visible .

Visibility of

In a single-threaded environment, if you write a value to a variable and read the variable without other write operations, you always get the same value. It sounds easy to understand. However, this is not the case when read and write operations are executed in different threads. In general, we cannot ensure that threads that perform read operations can see the values written by other threads at the right time, sometimes even impossible. In order to ensure the visibility of memory write operations between multiple threads, the synchronization mechanism must be used.

We use a small example to illustrate the errors that occur when multiple threads share data without synchronization. First look at the following code.

public class Novisibility {private static boolean ready;private static int number;private static class Readerthread Extend s thread{@Overridepublic void Run () {while (!ready) Thread.yield (); System.out.print (number);}} public static void Main (string[] args) throws Interruptedexception{new Readerthread (). Start (); number = 42;ready = true;}}

In code, both the main thread and the read thread will access the shared variables ready and number. The main thread starts the read thread, and then sets number to 42, and the ready is set to true. The read thread loops until the value of ready is found to true and then outputs the value of number. Although the novisibility looks like it will output 42, it is in fact likely to output 0, or it cannot be terminated at all. This is because there is no synchronization mechanism in the code and there is no guarantee that the ready and number values written by the main thread are visible to the read thread. Another more bizarre phenomenon is that novisibility may output 0 because the read thread might see a value written to ready, but not the value of the number after it is written, a phenomenon called "reordering (reordering)". As long as the reordering condition cannot be detected in a thread, it is not possible to ensure that the operations in the thread are executed in the order specified in the program. When the main thread first writes number and then writes to ready without synchronization, the read thread may see the exact reverse order of the write.

Note: In the absence of synchronization, the compiler, the processor, and the runtime can make some unexpected adjustments (reordering) of the order in which the operations are executed. In the absence of sufficient synchronization of multi-threaded programs, the relative memory operation of the execution sequence to judge, almost can not get the correct conclusion. Reordering may seem like a failed design, but it allows the JVM to take full advantage of the power of modern multi-core processors. For example, in the absence of synchronization, the Java memory model allows the compiler to reorder the order of operations and cache the values in registers. In addition, it allows the CPU to reorder the order of operations and cache the values in the processor-specific cache.

Failure data

Novisibility shows that a lack of synchronization can get an already defunct value: Failure data. Even worse, the failure value may not occur at the same time: one thread may get the most recent value of a variable, but it will get the invalid value of another variable. Sometimes to ensure visibility, just synchronizing the set method is not enough, and both the get and set methods need to be synchronized.

Non-atomic 64-bit operation

When a thread reads a variable without synchronization, it may get a failure value instead of a random value. This security guarantee is called minimum security (out-of-thin-air-safety).

The minimum security applies to most variables, but there is one exception: 64-bit numeric variables (double and long) of non-volatile types. The Java memory model requires that both read and write operations for variables must be atomic, but for long and double variables of non-volatile types, the JVM allows the decomposition of 64 read or write operations into two 32-bit operations. When reading a long variable of a non-volatile type, it is possible to read a high 32-bit value and a low 32-bit of another value. Therefore, it is not safe to use variables of shared and variable type long and double in multithreaded programs, even if the problem of failed data is not considered. Unless you declare them with keyword volatile, or protect them with locks.

Note: Although the JVM specification does not require 64-bit variable reads and writes to be atomic operations, now basically all commercial virtual machines implement them as atomic operations.

Volatile variable

The Java language provides a slightly weaker synchronization mechanism, the volatile variable, that is used to ensure that updates to variables are notified to other threads. When the variable is declared as volatile, the virtual machine will create a memory barrier (Memories Barrier or memory Fence) when the current instruction is run, preventing reordering of subsequent instructions to the location before the memory barrier. A volatile variable is a more lightweight synchronization mechanism than the Synchronized keyword.

Note: Memory barriers are not required when only one CPU accesses memory, but if two or more CPUs access the same piece of memory, and one is observing another, a memory barrier is required to ensure consistency.

Although the use of volatile variables is very convenient, but there are some limitations. It is usually used to mark the completion, interruption, or status of an operation. Although volatile variables can also be used to represent other state information, use it with great care. For example, the semantics of volatile are not sufficient to guarantee the atomicity of incrementing (count++) operations.


Java concurrency Programming (ii) visibility of objects

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.