• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Ron McLeod
  • paul wheaton
  • Jeanne Boyarsky
Sheriffs:
  • Paul Clapham
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
  • Himai Minh
Bartenders:

Difference between i++ and i=i++

 
Ranch Hand
Posts: 84
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi!. I know this is very basic but i'm very confused with this. I know that i++ change the value of i the next time thatit is used (unlike ++i). But i don't know why first it does not increase the value of the variable and then store it in "i".

This is one example:



As we can see at runtime, the "i" variable stores the value of 0 and println() method prints 0. I really expected another behavior.

On the other hand, i want to show you guys this code snippet that behaves as i expect, because in the same statement the value of b chages:

int b = 2;
System.out.println(b++ + 2 * b); // 8
 
Marshal
Posts: 80763
488
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Pablo Napoli wrote:. . . i'm very confused with this.

Don't let it worry you. Everybody else gets confused, too.

I know that i++ change the value of i the next time thatit is used (unlike ++i). But i don't know why first it does not increase the value of the variable and then store it in "i". . . .

Afraid that is incorrect. The increased value is indeed stored in i immediately, but the whole expression i++ has the old value of i. Then the assignment (=) overwrites the new value of i with the old value.
 
lowercase baba
Posts: 13091
67
Chrome Java Linux
  • Likes 2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
So many people get confused on this, we have a FAQ devoted to it.
 
Ranch Hand
Posts: 218
5
MS IE Notepad Suse
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
well, the reason is the order of execution with post-increment
post-in/decrement: the old value is read and then updated
pre-in/decrement: the value is first updated and then read

this means: i=i++ says in words: read the current value of i (0), then update i (this is whats called an atomic process) (new value: +1), and now final store the read value of 0 back to i
so, i, wich is atomic increment gets overridden by the previous read value - and hence is always 0

you other example works like this:
read b (2) and increase it (3), the add with (first multiply 2 with the new value of b (3) = (6)) = 8
so, as java evaluates from left to right, b gets first read with the value of 2 and is immediately incremented to 3 as pre/post in/decrements are atomic - and the, as math rule first multiply/devide the add/sub gets in the new updated value b, wich is now 3, gets multiplied with 2, wich is 6 l, and is then added with the old value 2 read before post-increment to result 8

once you get your head around these rules (atomics, left-to-right eval, preserve math rules) it's easy to eval such line with pen and paper
 
Pablo Napoli
Ranch Hand
Posts: 84
2
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you guys!. Having looked at those rules and the order of execution is easier than before following the flow of the program. Specially this part was very very clear:

this means: i=i++ says in words: read the current value of i (0), then update i (this is whats called an atomic process) (new value: +1), and now final store the read value of 0 back to i
so, i, wich is atomic increment gets overridden by the previous read value - and hence is always 0



Thanks!
 
Campbell Ritchie
Marshal
Posts: 80763
488
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Matt Wong wrote:well, the reason is the order of execution with post-increment . . .

Are you sure about that? Is that what it says in the Java® Language Specification (=JLS)? Look here. It doesn't say anything about order of execution, but says that the value of the whole expression is equal to the old value of the variable. I always look on it as meaning there are two values, the value of i and that of the whole expression i++.

. . . this is whats called an atomic process. . .

How do you know that x++ is atomic? I couldn't find anything in the JLS about ++ being atomic.
 
Saloon Keeper
Posts: 28713
211
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:How do you know that x++ is atomic? I couldn't find anything in the JLS about ++ being atomic.



I'm trying to find a way for it not to be atomic, and not succeeding.

At the Java level, "i++" is atomic in that it's a single operation and cannot be broken down into meaningful smaller components. You cannot inject any other operations into the function. You cannot even - unless I'm missing something - make postfix increment work on a sub-expression, only a single named variable. Or, I suppose on another pre/postfix operation.

At the bytecode level, I'm expecting (without checking) that there's an increment bytecode operator, so at that level, too, the operation would be atomic.

At the machine language level, things are murkier, since many machines also have an increment operator, but whether the increment operator can be the one and only machine instruction employed to realize the increment bytecode might vary depending on what sort of item you're post-incrementing. And on whether you're considering the target strictly as a register-only function or as a complete (updates memory) function. As an aside, on the IBM System/370 computers, pre-incrementing (and worse, pre-decrementing) is generally going to be more complicated at the instruction level than is post-incrementing, by there are many ways to implement these operations depending again on context.

Even given a single-instruction increment-memory-and-fetch machine instruction, it might be atomic at the machine code level but not at the microcode level, or in the case of a multiprocessor system at the bus level. Again, referencing the IBM instruction set, there were specific instructions guaranteed to be atomic at all levels, used for spin locks. It's been a long time since I looked at the Intel processor instruction set, but I seem to recall that they, too have such things. It's hard to run a multiprocessor system without something like that.

But, percolating back up to the Java source level, I'm pretty sure you're safe in considering pre- and post- increment/decrement subexpressions as "atomic", in the practical sense, if not in the formal sense for a single variable operand.

On the other hand, an expression such as "i++++" would not be atomic by those standards, so there's that. Now let's consider the saner version of that ("i += 2"). :) How atomic is that?
 
Campbell Ritchie
Marshal
Posts: 80763
488
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, the bytecode shows iinc 1, 1 as one stage, so you are probably right about ++ being executed as one operation. Whether that fulfils the formal definition of being immune from interference between competing accesses from multiple threads, I don't know. I presume the JLS would only call it atomic if it has that sort of immunity. I believe that = is atomic (not for longs and doubles), but I am not sure.
The JLS says that compound assignment is equivalent to casting, so, even if you optimise away the identity conversion, you have two stages the addition and the assignment. If I change the middle line to ++i; or i += 1;, neither seems to make any difference to the bytecode, and changing to i += 2; turns the line 3 to 3: iinc 1, 2. So it would appear the compiler can optimise the += away. That no longer works if I force the implicit cast by declaring i as a short in line 5.I presume the cast is instruction 6, but now the += seems to become a multi‑stage operation.
 
Sheriff
Posts: 7126
185
Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Does AtomicInteger fulfil the requirements?

https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/concurrent/atomic/AtomicInteger.html
 
Campbell Ritchie
Marshal
Posts: 80763
488
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, AtomicInteger has all its methods atomic. According to the Sierra/Bates/Robson OCP8 study guide it uses a different chip instruction from the usual iadd. Can't remember any more details just at the moment.
 
Master Rancher
Posts: 5175
83
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Holloway wrote:But, percolating back up to the Java source level, I'm pretty sure you're safe in considering pre- and post- increment/decrement subexpressions as "atomic", in the practical sense, if not in the formal sense for a single variable operand.



Not at the Java level either, once multithreading is considered.  The Java memory model described in the JLS makes no guarantees that would imply that an increment operation could be considered atomic.  And at a purely practical level, it's not difficult to observe in action:

Typical output for me:

If you don't see similar results, try increasing the numThreads or numIncrementsPerThread.  And note that I made primitiveInt volatile too, to see if that helped.  It didn't.
 
Sheriff
Posts: 9021
656
Mac OS X Spring VI Editor BSD Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Pablo Napoli,

CowGratulations, your topic has been published in our CodeRanch Journal August Edition.

A copy of journal you could find here -> https://coderanch.com/wiki/715405/CodeRanch-Journal-August
Other than that, you, as everybody else supposed to get one emailed to you
reply
    Bookmark Topic Watch Topic
  • New Topic