Java volatile variable doesn't behave correctly.












5















public class MyThread
{
volatile static int i;

public static class myT extends Thread
{
public void run ()
{
int j = 0;
while(j<1000000){
i++;
j++;
}
}
}

public static void main (String argv)
throws InterruptedException{
i = 0;

Thread my1 = new myT();
Thread my2 = new myT();
my1.start();
my2.start();

my1.join();
my2.join();

System.out.println("i = "+i);
}
}


Since volatile builds happens-before relationship, the final value of i should be strictly 2000000. However, the actual result is nothing different from being without volatile for variable i. Can anyone explanation why it doesn't work here? Since i is declared volatile, it should be protected from memory inconsistency.










share|improve this question



























    5















    public class MyThread
    {
    volatile static int i;

    public static class myT extends Thread
    {
    public void run ()
    {
    int j = 0;
    while(j<1000000){
    i++;
    j++;
    }
    }
    }

    public static void main (String argv)
    throws InterruptedException{
    i = 0;

    Thread my1 = new myT();
    Thread my2 = new myT();
    my1.start();
    my2.start();

    my1.join();
    my2.join();

    System.out.println("i = "+i);
    }
    }


    Since volatile builds happens-before relationship, the final value of i should be strictly 2000000. However, the actual result is nothing different from being without volatile for variable i. Can anyone explanation why it doesn't work here? Since i is declared volatile, it should be protected from memory inconsistency.










    share|improve this question

























      5












      5








      5








      public class MyThread
      {
      volatile static int i;

      public static class myT extends Thread
      {
      public void run ()
      {
      int j = 0;
      while(j<1000000){
      i++;
      j++;
      }
      }
      }

      public static void main (String argv)
      throws InterruptedException{
      i = 0;

      Thread my1 = new myT();
      Thread my2 = new myT();
      my1.start();
      my2.start();

      my1.join();
      my2.join();

      System.out.println("i = "+i);
      }
      }


      Since volatile builds happens-before relationship, the final value of i should be strictly 2000000. However, the actual result is nothing different from being without volatile for variable i. Can anyone explanation why it doesn't work here? Since i is declared volatile, it should be protected from memory inconsistency.










      share|improve this question














      public class MyThread
      {
      volatile static int i;

      public static class myT extends Thread
      {
      public void run ()
      {
      int j = 0;
      while(j<1000000){
      i++;
      j++;
      }
      }
      }

      public static void main (String argv)
      throws InterruptedException{
      i = 0;

      Thread my1 = new myT();
      Thread my2 = new myT();
      my1.start();
      my2.start();

      my1.join();
      my2.join();

      System.out.println("i = "+i);
      }
      }


      Since volatile builds happens-before relationship, the final value of i should be strictly 2000000. However, the actual result is nothing different from being without volatile for variable i. Can anyone explanation why it doesn't work here? Since i is declared volatile, it should be protected from memory inconsistency.







      java concurrency volatile






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Apr 29 '13 at 23:39









      OneZeroOneZero

      4,23084167




      4,23084167
























          1 Answer
          1






          active

          oldest

          votes


















          8















          Can anyone explanation why it doesn't work here? Since i is declared volatile, it should be protected from memory inconsistency.




          It is protected but unfortunately i++ is not an atomic operation. It is actually read/increment/store. So volatile is not going to save you from the race conditions between threads. You might get the following order of operations from your program:




          1. thread #1 reads i, gets 10

          2. right afterwards, thread #2 reads i, gets 10

          3. thread #1 increments i to 11

          4. thread #2 increments i to 11

          5. thread #1 stores 11 to i

          6. thread #2 stores 11 to i


          As you can see, even though 2 increments have happened and the value has been properly synchronized between threads, the race condition means the value only went up by 1. See this nice looking explanation. Here's another good answer: Is a volatile int in Java thread-safe?



          What you should be using are AtomicInteger which allows you to safely increment from multiple threads.



          static final AtomicInteger i = new AtomicInteger(0);
          ...
          for (int j = 0; j<1000000; j++) {
          i.incrementAndGet();
          }





          share|improve this answer





















          • 1





            Only i needs to be an AtomicInteger; j is purely local to the thread.

            – Mel Nicholson
            Apr 29 '13 at 23:44








          • 1





            I'm not sure how to answer @OneZero. Declaring it as volatile won't work because ++ is not atomic. You could synchronize on it every time you update it or use AtomicInteger. Making it volatile isn't enough.

            – Gray
            Apr 29 '13 at 23:46






          • 2





            @OneZero docs.oracle.com/javase/tutorial/essential/concurrency/… should explain a bit about what volitile is for. Not this.

            – Mel Nicholson
            Apr 29 '13 at 23:47








          • 1





            @OneZero a non-volitile read can get some bits for the pre-write value, and others from a post-write value, but only for types larger than a word on the underlying memory. double is the most common offender. Generally speaking, most concurrency issues are too much for volatile so look at synchronize and wait instead.

            – Mel Nicholson
            Apr 29 '13 at 23:55






          • 1





            @Gray In practice on anything build this millenium, probably true. I don't think the guarantee is in the language spec, though. Perhaps a more practical guarantee is that write-order is preserved, so if you have a double data and a volitile boolean ready and code that sets data first and ready = true second, it is certain that after you see ready turn to true, data will also have been set, even in a different thread. This is not guaranteed without the volatile keyword, where you can see ready true and then the value of data may not have propagated from the write thread.

            – Mel Nicholson
            Apr 30 '13 at 0:03











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f16289983%2fjava-volatile-variable-doesnt-behave-correctly%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          8















          Can anyone explanation why it doesn't work here? Since i is declared volatile, it should be protected from memory inconsistency.




          It is protected but unfortunately i++ is not an atomic operation. It is actually read/increment/store. So volatile is not going to save you from the race conditions between threads. You might get the following order of operations from your program:




          1. thread #1 reads i, gets 10

          2. right afterwards, thread #2 reads i, gets 10

          3. thread #1 increments i to 11

          4. thread #2 increments i to 11

          5. thread #1 stores 11 to i

          6. thread #2 stores 11 to i


          As you can see, even though 2 increments have happened and the value has been properly synchronized between threads, the race condition means the value only went up by 1. See this nice looking explanation. Here's another good answer: Is a volatile int in Java thread-safe?



          What you should be using are AtomicInteger which allows you to safely increment from multiple threads.



          static final AtomicInteger i = new AtomicInteger(0);
          ...
          for (int j = 0; j<1000000; j++) {
          i.incrementAndGet();
          }





          share|improve this answer





















          • 1





            Only i needs to be an AtomicInteger; j is purely local to the thread.

            – Mel Nicholson
            Apr 29 '13 at 23:44








          • 1





            I'm not sure how to answer @OneZero. Declaring it as volatile won't work because ++ is not atomic. You could synchronize on it every time you update it or use AtomicInteger. Making it volatile isn't enough.

            – Gray
            Apr 29 '13 at 23:46






          • 2





            @OneZero docs.oracle.com/javase/tutorial/essential/concurrency/… should explain a bit about what volitile is for. Not this.

            – Mel Nicholson
            Apr 29 '13 at 23:47








          • 1





            @OneZero a non-volitile read can get some bits for the pre-write value, and others from a post-write value, but only for types larger than a word on the underlying memory. double is the most common offender. Generally speaking, most concurrency issues are too much for volatile so look at synchronize and wait instead.

            – Mel Nicholson
            Apr 29 '13 at 23:55






          • 1





            @Gray In practice on anything build this millenium, probably true. I don't think the guarantee is in the language spec, though. Perhaps a more practical guarantee is that write-order is preserved, so if you have a double data and a volitile boolean ready and code that sets data first and ready = true second, it is certain that after you see ready turn to true, data will also have been set, even in a different thread. This is not guaranteed without the volatile keyword, where you can see ready true and then the value of data may not have propagated from the write thread.

            – Mel Nicholson
            Apr 30 '13 at 0:03
















          8















          Can anyone explanation why it doesn't work here? Since i is declared volatile, it should be protected from memory inconsistency.




          It is protected but unfortunately i++ is not an atomic operation. It is actually read/increment/store. So volatile is not going to save you from the race conditions between threads. You might get the following order of operations from your program:




          1. thread #1 reads i, gets 10

          2. right afterwards, thread #2 reads i, gets 10

          3. thread #1 increments i to 11

          4. thread #2 increments i to 11

          5. thread #1 stores 11 to i

          6. thread #2 stores 11 to i


          As you can see, even though 2 increments have happened and the value has been properly synchronized between threads, the race condition means the value only went up by 1. See this nice looking explanation. Here's another good answer: Is a volatile int in Java thread-safe?



          What you should be using are AtomicInteger which allows you to safely increment from multiple threads.



          static final AtomicInteger i = new AtomicInteger(0);
          ...
          for (int j = 0; j<1000000; j++) {
          i.incrementAndGet();
          }





          share|improve this answer





















          • 1





            Only i needs to be an AtomicInteger; j is purely local to the thread.

            – Mel Nicholson
            Apr 29 '13 at 23:44








          • 1





            I'm not sure how to answer @OneZero. Declaring it as volatile won't work because ++ is not atomic. You could synchronize on it every time you update it or use AtomicInteger. Making it volatile isn't enough.

            – Gray
            Apr 29 '13 at 23:46






          • 2





            @OneZero docs.oracle.com/javase/tutorial/essential/concurrency/… should explain a bit about what volitile is for. Not this.

            – Mel Nicholson
            Apr 29 '13 at 23:47








          • 1





            @OneZero a non-volitile read can get some bits for the pre-write value, and others from a post-write value, but only for types larger than a word on the underlying memory. double is the most common offender. Generally speaking, most concurrency issues are too much for volatile so look at synchronize and wait instead.

            – Mel Nicholson
            Apr 29 '13 at 23:55






          • 1





            @Gray In practice on anything build this millenium, probably true. I don't think the guarantee is in the language spec, though. Perhaps a more practical guarantee is that write-order is preserved, so if you have a double data and a volitile boolean ready and code that sets data first and ready = true second, it is certain that after you see ready turn to true, data will also have been set, even in a different thread. This is not guaranteed without the volatile keyword, where you can see ready true and then the value of data may not have propagated from the write thread.

            – Mel Nicholson
            Apr 30 '13 at 0:03














          8












          8








          8








          Can anyone explanation why it doesn't work here? Since i is declared volatile, it should be protected from memory inconsistency.




          It is protected but unfortunately i++ is not an atomic operation. It is actually read/increment/store. So volatile is not going to save you from the race conditions between threads. You might get the following order of operations from your program:




          1. thread #1 reads i, gets 10

          2. right afterwards, thread #2 reads i, gets 10

          3. thread #1 increments i to 11

          4. thread #2 increments i to 11

          5. thread #1 stores 11 to i

          6. thread #2 stores 11 to i


          As you can see, even though 2 increments have happened and the value has been properly synchronized between threads, the race condition means the value only went up by 1. See this nice looking explanation. Here's another good answer: Is a volatile int in Java thread-safe?



          What you should be using are AtomicInteger which allows you to safely increment from multiple threads.



          static final AtomicInteger i = new AtomicInteger(0);
          ...
          for (int j = 0; j<1000000; j++) {
          i.incrementAndGet();
          }





          share|improve this answer
















          Can anyone explanation why it doesn't work here? Since i is declared volatile, it should be protected from memory inconsistency.




          It is protected but unfortunately i++ is not an atomic operation. It is actually read/increment/store. So volatile is not going to save you from the race conditions between threads. You might get the following order of operations from your program:




          1. thread #1 reads i, gets 10

          2. right afterwards, thread #2 reads i, gets 10

          3. thread #1 increments i to 11

          4. thread #2 increments i to 11

          5. thread #1 stores 11 to i

          6. thread #2 stores 11 to i


          As you can see, even though 2 increments have happened and the value has been properly synchronized between threads, the race condition means the value only went up by 1. See this nice looking explanation. Here's another good answer: Is a volatile int in Java thread-safe?



          What you should be using are AtomicInteger which allows you to safely increment from multiple threads.



          static final AtomicInteger i = new AtomicInteger(0);
          ...
          for (int j = 0; j<1000000; j++) {
          i.incrementAndGet();
          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited May 23 '17 at 10:25









          Community

          11




          11










          answered Apr 29 '13 at 23:41









          GrayGray

          95.9k14229298




          95.9k14229298








          • 1





            Only i needs to be an AtomicInteger; j is purely local to the thread.

            – Mel Nicholson
            Apr 29 '13 at 23:44








          • 1





            I'm not sure how to answer @OneZero. Declaring it as volatile won't work because ++ is not atomic. You could synchronize on it every time you update it or use AtomicInteger. Making it volatile isn't enough.

            – Gray
            Apr 29 '13 at 23:46






          • 2





            @OneZero docs.oracle.com/javase/tutorial/essential/concurrency/… should explain a bit about what volitile is for. Not this.

            – Mel Nicholson
            Apr 29 '13 at 23:47








          • 1





            @OneZero a non-volitile read can get some bits for the pre-write value, and others from a post-write value, but only for types larger than a word on the underlying memory. double is the most common offender. Generally speaking, most concurrency issues are too much for volatile so look at synchronize and wait instead.

            – Mel Nicholson
            Apr 29 '13 at 23:55






          • 1





            @Gray In practice on anything build this millenium, probably true. I don't think the guarantee is in the language spec, though. Perhaps a more practical guarantee is that write-order is preserved, so if you have a double data and a volitile boolean ready and code that sets data first and ready = true second, it is certain that after you see ready turn to true, data will also have been set, even in a different thread. This is not guaranteed without the volatile keyword, where you can see ready true and then the value of data may not have propagated from the write thread.

            – Mel Nicholson
            Apr 30 '13 at 0:03














          • 1





            Only i needs to be an AtomicInteger; j is purely local to the thread.

            – Mel Nicholson
            Apr 29 '13 at 23:44








          • 1





            I'm not sure how to answer @OneZero. Declaring it as volatile won't work because ++ is not atomic. You could synchronize on it every time you update it or use AtomicInteger. Making it volatile isn't enough.

            – Gray
            Apr 29 '13 at 23:46






          • 2





            @OneZero docs.oracle.com/javase/tutorial/essential/concurrency/… should explain a bit about what volitile is for. Not this.

            – Mel Nicholson
            Apr 29 '13 at 23:47








          • 1





            @OneZero a non-volitile read can get some bits for the pre-write value, and others from a post-write value, but only for types larger than a word on the underlying memory. double is the most common offender. Generally speaking, most concurrency issues are too much for volatile so look at synchronize and wait instead.

            – Mel Nicholson
            Apr 29 '13 at 23:55






          • 1





            @Gray In practice on anything build this millenium, probably true. I don't think the guarantee is in the language spec, though. Perhaps a more practical guarantee is that write-order is preserved, so if you have a double data and a volitile boolean ready and code that sets data first and ready = true second, it is certain that after you see ready turn to true, data will also have been set, even in a different thread. This is not guaranteed without the volatile keyword, where you can see ready true and then the value of data may not have propagated from the write thread.

            – Mel Nicholson
            Apr 30 '13 at 0:03








          1




          1





          Only i needs to be an AtomicInteger; j is purely local to the thread.

          – Mel Nicholson
          Apr 29 '13 at 23:44







          Only i needs to be an AtomicInteger; j is purely local to the thread.

          – Mel Nicholson
          Apr 29 '13 at 23:44






          1




          1





          I'm not sure how to answer @OneZero. Declaring it as volatile won't work because ++ is not atomic. You could synchronize on it every time you update it or use AtomicInteger. Making it volatile isn't enough.

          – Gray
          Apr 29 '13 at 23:46





          I'm not sure how to answer @OneZero. Declaring it as volatile won't work because ++ is not atomic. You could synchronize on it every time you update it or use AtomicInteger. Making it volatile isn't enough.

          – Gray
          Apr 29 '13 at 23:46




          2




          2





          @OneZero docs.oracle.com/javase/tutorial/essential/concurrency/… should explain a bit about what volitile is for. Not this.

          – Mel Nicholson
          Apr 29 '13 at 23:47







          @OneZero docs.oracle.com/javase/tutorial/essential/concurrency/… should explain a bit about what volitile is for. Not this.

          – Mel Nicholson
          Apr 29 '13 at 23:47






          1




          1





          @OneZero a non-volitile read can get some bits for the pre-write value, and others from a post-write value, but only for types larger than a word on the underlying memory. double is the most common offender. Generally speaking, most concurrency issues are too much for volatile so look at synchronize and wait instead.

          – Mel Nicholson
          Apr 29 '13 at 23:55





          @OneZero a non-volitile read can get some bits for the pre-write value, and others from a post-write value, but only for types larger than a word on the underlying memory. double is the most common offender. Generally speaking, most concurrency issues are too much for volatile so look at synchronize and wait instead.

          – Mel Nicholson
          Apr 29 '13 at 23:55




          1




          1





          @Gray In practice on anything build this millenium, probably true. I don't think the guarantee is in the language spec, though. Perhaps a more practical guarantee is that write-order is preserved, so if you have a double data and a volitile boolean ready and code that sets data first and ready = true second, it is certain that after you see ready turn to true, data will also have been set, even in a different thread. This is not guaranteed without the volatile keyword, where you can see ready true and then the value of data may not have propagated from the write thread.

          – Mel Nicholson
          Apr 30 '13 at 0:03





          @Gray In practice on anything build this millenium, probably true. I don't think the guarantee is in the language spec, though. Perhaps a more practical guarantee is that write-order is preserved, so if you have a double data and a volitile boolean ready and code that sets data first and ready = true second, it is certain that after you see ready turn to true, data will also have been set, even in a different thread. This is not guaranteed without the volatile keyword, where you can see ready true and then the value of data may not have propagated from the write thread.

          – Mel Nicholson
          Apr 30 '13 at 0:03


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f16289983%2fjava-volatile-variable-doesnt-behave-correctly%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

          Calculate evaluation metrics using cross_val_predict sklearn

          Insert data from modal to MySQL (multiple modal on website)