Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
203 views
in Technique[技术] by (71.8m points)

java - Implement Acquire/Release model by using volatile in java8

In my case, I want to implement the Acquire/Release model in java8 with volatile.

So I write the code that uses a volatile shared variable I to guarantee the modifying of MAP could be seen by other threads.

public static volatile int I = 0;

public static final Map<String, String> MAP = new HashMap<>();

// run at Thread-1
public static void write(){
    MAP.put("test", "test");
    I++;                      // release
}

// run at Thead-2
public static void read(){
    int i = I;                // acquire
    MAP.get("test");          // want to see the modifying by write()
}

My question is that:

  1. Is the code synchronize correctly?
  2. Is it possible that JIT eliminates the unused local variable i so that the acquire operation is invalid?
question from:https://stackoverflow.com/questions/65951795/implement-acquire-release-model-by-using-volatile-in-java8

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

First note that ++ on a volatile variable is not atomic, hence, you can’t rely on its value in case of multiple updates.

As long as there is only a single update, it may be sufficient to check whether the update did happen, but it is crucial to perform the check. Otherwise, there is no guaranty that the (supposed to be acquire) volatile read is subsequent to the (supposed to be release) volatile update.

Just consider the following timing:

      Thread 1        Thread 2

    ┌            ┐    [ Read I    ]
    │ map update │    ┌           ┐    
    └            ┘    │ map query │
    [ Write I    ]    └           ┘

Here, the two threads use the map concurrently, which is hopelessly broken, while the acquire and release actions have no consequences, as the acquire is not subsequent to the release.

You can only rely on this relationship if you check the value you’ve read and proceed only when it is the expected value written by the other thread.


Since the whole construct would work only for a single update, you can use a boolean instead:

private static volatile boolean I = false;

private static final Map<String, String> MAP = new HashMap<>();

// run at Thread-1
public static void write(){
    MAP.put("test", "test");
    I = true;                      // release
}

// run at Thead-2
public static void read(){
    if(I) {                // acquire
        MAP.get("test");          // want to see the modifying by write()
    }
}

You can not use this for more than one update, as the thread wanting to perform a second update must ensure not to start updating the map before all threads reading the map after the first update have completed. But this information is not available at all with this approach.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...