开发者

Do I need to use volatile, if 2 different write and read thread will never alive at the same time

开发者 https://www.devze.com 2023-02-06 19:51 出处:网络
By referring to http://www.javamex.com/tutorials/synchronization_volatile.shtml, I am not sure whether I need to use volatile keyword in the following case, due to additional rule 3.

By referring to http://www.javamex.com/tutorials/synchronization_volatile.shtml, I am not sure whether I need to use volatile keyword in the following case, due to additional rule 3.

  1. A primitive static variable will be write by Thread A.
  2. The same primitive static variable will be read by Thread B.
  3. Thread B will only run, after Thread A is "dead". ("dead" means, the last statement of Thread A's void run is finished)

Will the new value written by Thread A, will always committed to main memory, after it "dead"? If yes, does it mean I need not volatile keyword if the above 3 conditions are meet?

I am doubt that volatile is being required in this case. As it is required, then ArrayList may broken. As one thread may perform insert and update size member variable. Later, another thread (not-concurrently) may read the ArrayList's size. If you look at ArrayList source code, size is not being declared as volatile.

In JavaDoc of ArrayList, then only mention that ArrayList is not safe to be used for multiple threads access an ArrayList instance co开发者_开发技巧ncurrently, but not for multiple threads access an ArrayList instance at different timing.

Let me use the following code to issulate this problem

public static void main(String[] args) throws InterruptedException {
    // Create and start the thread
    final ArrayList<String> list = new ArrayList<String>();
    Thread writeThread = new Thread(new Runnable() {
        public void run() {
            list.add("hello");
        }
    });
    writeThread.join();
    Thread readThread = new Thread(new Runnable() {
        public void run() {
            // Does it guarantee that list.size will always return 1, as this list
            // is manipulated by different thread?
            // Take note that, within implementation of ArrayList, member
            // variable size is not marked as volatile.
            assert(1 == list.size());
        }
    });
    readThread.join();
}


Yes, you still need to use volatile (or some other form of synchronization).

The reason why is that the two threads could run on different processors and even if one thread has long finished before the other starts there is no guarantee that the second thread will get the freshest value when it makes the read. If the field is not marked as volatile and no other synchronization is used, then the second thread could get a value that was cached locally on the processor it is running on. That cached value could in theory be out-of-date for a long period of time, including after the first thread completed.

If you use volatile the value will always be written to and read from main memory, bypassing the processor's cached value.


No, you may not need it. despite Mark Byers answer begin fairly accurate, it is limited. synchronized and volatile are not the only ways to correctly pass data between threads. there are other, less talked about "synchronization points". specifically, thread start and thread end are synchronization points. however, the thread which is starting Thread B must have recognized that Thread A is finished (e.g. by joining the thread or checking the thread's state). if this is the case, the the variable does not need to be volatile.


Possibly yes, unless you manually create a memory barrier. If A sets the variable, and B decides to take oit from some registry, you have a problem. So, you need a mmemory barrier, either implicit (lock, volatile) or explicit.


http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4.4

The final action in a thread T1 synchronizes-with any action in another thread T2 that detects that T1 has terminated. T2 may accomplish this by calling T1.isAlive() or T1.join().

So it is possible to achieve your goal without using volatile.

In many cases, when there are apparent time dependencies, synchronization is being done by someone under the hood, and application doesn't need extra synchronization. Unfortunately this is not the rule, programmers must analyze each case carefully.

One example is Swing worker thread. People would do some calculation in a worker thread, save the result to a variable, then raise an event. The event thread will then read the result of the calculation from the variable. No explicit synchronization is needed from application code, because "raising an event" already did synchronization, so writes from worker thread is visible from event thread.

On one hand, this is a bliss. On the other hand, many people didn't understand this, they omit the synchronization simply because they never thought about the issue. Their programs happen to be correct... this time.


If Thread A definitely dies before Thread B starts reading then it would be possible to avoid using volatile

eg.

public class MyClass {

   volatile int x = 0;

   public static void main(String[] args) {

      final int i = x;
      new Thread() {
         int j = i;
         public void run() {
            j = 10;
            final int k = j;
            new Thread() {
               public void run() {
                  MyClass.x = k;
               }               
            }.start();
         }
      }.start();
   }
}

However, the problem is that whichever Thread starts Thread B will need to now that the value that Thread A is writing to has changed and to not use its own cached version. The easiest way to do this is to get Thread A to spawn Thread B. But if Thread A has nothing else to do when it spawns Thread B then this seems a little pointless (why not just use the same thread).

The other alternative is that if no other thread is dependent on this variable then maybe Thread A could initial a local variable with the volatile variable, do what it needs to do, and then finally write the contents of its local variable back to the volatile variable. Then when Thread B starts it initialises its local variable from the volatile variable and reads only from its local variable thereafter. This should massively reduce the amount of time spent keeping the volatile variable in sync. If this solution seems unacceptable (because of other threads writing to the volatile variable or whatever) then you definitely need to declare the variable volatile.

0

精彩评论

暂无评论...
验证码 换一张
取 消