Java – multithreaded access and variable caching for threads

If I read a complete chapter / book on multithreading, I can find the answer, but I want a faster answer (I know this stackoverflow problem is similar, but not enough.)

Suppose you have this class:

public class TestClass {
   private int someValue;

   public int getSomeValue() { return someValue; }
   public void setSomeValue(int value) {  someValue = value; }
}

Two threads (A and b) access instances of this class Consider the following order:

> A:getSomeValue() > B:setSomeValue() > A:getSomeValue()

If I'm right, somevalue must be volatile, otherwise step 3 may not return the latest value (because a may have a cached value) Is it correct?

The second case:

> B:setSomeValue() > A:getSomeValue()

In this case, a will always get the correct value because this is its first access, so he has not cached the value yet Is this correct?

If the class is accessed only in the second way, volatile / synchronization is not required, or is it?

Please note that this example is simplified. In fact, I want to know the specific member variables and methods in a complex class, not the whole class (that is, which variables should be volatile or have synchronous access) The point is: if more threads access some data, does it need to be accessed synchronously in all ways, or depends on how they access it (such as orders)?

After reading the comments, I try to illustrate the source of my confusion with another example:

>From UI thread: threada Start() > threada calls getsomevalue() and tells the UI thread > UI thread to get the message (in its message queue), so it calls: threadb Start() > threadb calls setsomevalue(), and informs the UI thread > UI thread to get the message, and informs threada (in some way, such as message queue) > threada to call getsomevalue()

This is a fully synchronous structure, but why does this mean that threada will get the latest value in step 6? (if somevalue is not volatile, or is not placed in the monitor when accessed from anywhere)

Solution

The problem is that Java is just a specification There are many examples of JVM implementations and physical operating environments On any given combination, the action may be safe or unsafe For example, on a single processor system, the volatile keyword in the example may not be necessary at all Since the authors of memory and language specifications cannot reasonably consider the possible set of operating conditions, they choose to whitelist some patterns, which can be guaranteed to be applicable to all compatible implementations Following these guidelines ensures that your code runs on the target system and can be ported reasonably

In this case, "caching" usually refers to activities at the hardware level There are events in Java that cause the core on a multiprocessor system to "synchronize" its cache Accessing volatile variables is one example, and synchronized blocks are another Imagine that these two threads X and y are scheduled to run on different processors

X starts and is scheduled on proc 1
y starts and is scheduled on proc 2

.. Now you have two threads executing simultaneously
to speed things up the processors check local caches
before going to main memory because its expensive.

x calls setSomeValue('x-value') //assuming proc 1's cache is empty the cache is set
                                //this value is dropped on the bus to be flushed
                                //to main memory
                                //Now all get's will retrieve from cache instead
                                //of engaging the memory bus to go to main memory 
y calls setSomeValue('y-value') //same thing happens for proc 2

//Now in this situation depending on to order in which things are scheduled and
//what thread you are calling from calls to getSomeValue() may return 'x-value' or
//'y-value. The results are completely unpredictable.

The key is volatile (on a compatible Implementation) to ensure that ordered writes will always be flushed to main memory, and the cache of other processors will be marked as "dirty" before the next access, regardless of the thread on which the access occurs

Disclaimer: volatile does not lock This is particularly important when:

volatile int counter;

public incrementSomeValue(){
    counter++; // Bad thread juju - this is at least three instructions 
               // read - increment - write             
               // there is no guarantee that this operation is atomic
}

If your intention is to always call setSomeValue before getSomeValue, this may be related to your problem.

If the intent is that getsomevalue () must always reflect the most recent call to setsomevalue (), then this is a good place to use the volatile keyword Remember that without it, even if setsomevalue() is scheduled first, there is no guarantee that getsomevalue() will reflect the most recent call to setsomevalue()

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>