This was an interview question , any help would be appreciated
How do you synchronize two threads, out of which one increments a value and the the other displays it ( P.S. the thread which displays the value must only display a value when its a new value )
Ex : int x = 5;
T1 : increments it to 6
T2 : must display 6 ( only once ) and must display it again when it becomes 7
I answered that I would use a semaphore something like:
int c=0; // variable that I used to synchronize
// In T1
if( c = 0 )
{
c++;
x++; // value that is incremented
}
// in T2
if( c == 1 )
{
cout<<x;
c--;
}
He then asked what would you do if there's a context switch from thread T1 to T2 after setting c to 1 but before incrementing x ( As in that case it would enter P2 before incrementing x )
I couldn't answer this part. Any help would be appreciated.
This is a classic use case for a condition variable with the slight hitch that the value can easily update more than once in thread 1 before thread 2 runs to handle it:
// In some scope common to both threads
int c_ = 0; // variable
std::mutex mutex_();
std::condition_variable cond_();
// Thread 1
{
std::lock_guard<std::mutex> lock(mutex_);
++c_;
}
cond_.notify_one();
// Thread 2
{
std::lock_guard<std::mutex> lock( mutex_ );
int cLocal = c_;
while ( !done ) {
cond_.wait( lock, [] { return c_ != cLocal; } );
while ( cLocal++ < c_ )
... // Display new *local* value
}
}
Nice exercise.
You haven't specified the c++ tag in the question, but the question itself contains cout<<x, so you were probably interviewing for a C++ position. Despite that, I'm going to answer in Java since this is an interview question and language shouldn't matter much as long as I avoid using anything too specific to Java.
As your interviewer pointed out, the synchronization has to happen in both directions:
The printing thread must wait for the incrementing thread to finish its job
The incrementing thread must wait for the printing thread to finish its job
So we need something to let us know that the printer is done (so the incrementer can run), and another to let us know that the incrementer is done. I used two semaphores for that:
Working version on Ideone
import java.util.concurrent.Semaphore;
class IncrementDemo {
static int x = 0;
public static void main(String[] args) {
Semaphore incrementLock = new Semaphore(0);
Semaphore printLock = new Semaphore(0);
Thread incrementer = new Thread(() -> {
for(;;) {
incrementLock.acquire(); //Wait to be allowed to increment
x++;
printLock.release(); //Allow the printer to print
}
});
Thread printer = new Thread(() -> {
for (;;) {
incrementLock.release(); //Let the incrementer to its job
printLock.acquire(); //Wait to be allowed to print
System.out.println(x);
}
});
incrementer.setDaemon(false); //Keep the program alive after main() exits
printer.setDaemon(false);
incrementer.start(); //Start both threads
printer.start();
}
}
(I removed the try/catch blocks around acquire for readability).
Output:
1
2
3
4
5
6
7
...
Problems:
There are 2 main problems with parallel code in general.
1. Atomicity
The smallest granularity in code are in fact not the single operations like i++, but the underlying assembly-instructions. Therefore every operation, which involves a write, may not be called from multiple threads. (this differs heavily on your target architecture, but x86 is in contrast to arm64 very restrictive)
But luckily c++ provides the std::atomic operations, which give you a nice plattform independent way to modify variables from multiple threads.
2. Consistency
Both the compiler and the processor are allowed to reorder any instruction as long the consistency of the local thread is preserved. So what does this mean?
Take a look at your first thread
if( c = 0 )
{
c++;
x++; // value that is incremented
}
You have 3 operations c == 0, c++ and x++. Both increments do not depend from each other, hence the compiler would be allowed to swap them. At runtime the core may reorder them too, leaving you in very vague situation. In a sequential world this is perfectly fine and improves the overall performance (unless it leads to security holes like meltdown). Unfortunately neither the compiler or the cpu recognize parallel code, therefore any optimization may break your parallel program.
But once again, c++ provides a built-in solution for this problem called std::memory_order, which enforces are specific consistency-model.
Solutions:
Simple mutex:
A mutex is a simple, but powerfull tool. It solves the problems with Atomicity and Consistency by providing so called critical sections, which prevent parallel execution. This means, that in the given example the if-clause in both threads are sequential and will never be executed in parallel.
The implementation works, but has a flaw. If one of the threads is very slow, the other one will waste a lot of cpu-time by continous checking the newValue flag.
#include <mutex>
std::mutex mutex;
int value = true;
bool newValue = false;
void producer_thread() {
while(true) {
std::lock_guard<std::mutex> lg(mutex);
if (newValue == false) {
value++;
newValue = true;
}
}
}
void consumer_thread() {
while(true) {
std::lock_guard<std::mutex> lg(mutex);
if (newValue == true) {
std::cout << value;
newValue = false;
}
}
}
Condition Variable:
A condition variable is basically just a "wait-for-notify"-construct. You can block the current execution by calling wait until an other thread calls notify. This implementation would be the go-to scenario.
#include <mutex>
#include <condition_variable>
std::mutex mutex;
std::condition_variable cond;
int value = true;
bool newValue = false;
void producer() {
while(true) {
std::unique_lock<std::mutex> ul(mutex);
while (newValue == true) {
cond.wait(ul);
}
value++;
newValue = true;
cond.notify_all();
}
}
void consumer() {
while(true) {
std::unique_lock<std::mutex> ul(mutex);
while (newValue == false) {
cond.wait(ul);
}
std::cout << value;
newValue = false;
cond.notify_all();
}
}
Related
Why is i++ not atomic in Java?
To get a bit deeper in Java I tried to count how often the loop in threads are executed.
So I used a
private static int total = 0;
in the main class.
I have two threads.
Thread 1: Prints System.out.println("Hello from Thread 1!");
Thread 2: Prints System.out.println("Hello from Thread 2!");
And I count the lines printed by thread 1 and thread 2. But the lines of thread 1 + lines of thread 2 don't match the total number of lines printed out.
Here is my code:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Test {
private static int total = 0;
private static int countT1 = 0;
private static int countT2 = 0;
private boolean run = true;
public Test() {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
newCachedThreadPool.execute(t1);
newCachedThreadPool.execute(t2);
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
run = false;
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println((countT1 + countT2 + " == " + total));
}
private Runnable t1 = new Runnable() {
#Override
public void run() {
while (run) {
total++;
countT1++;
System.out.println("Hello #" + countT1 + " from Thread 2! Total hello: " + total);
}
}
};
private Runnable t2 = new Runnable() {
#Override
public void run() {
while (run) {
total++;
countT2++;
System.out.println("Hello #" + countT2 + " from Thread 2! Total hello: " + total);
}
}
};
public static void main(String[] args) {
new Test();
}
}
i++ is probably not atomic in Java because atomicity is a special requirement which is not present in the majority of the uses of i++. That requirement has a significant overhead: there is a large cost in making an increment operation atomic; it involves synchronization at both the software and hardware levels that need not be present in an ordinary increment.
You could make the argument that i++ should have been designed and documented as specifically performing an atomic increment, so that a non-atomic increment is performed using i = i + 1. However, this would break the "cultural compatibility" between Java, and C and C++. As well, it would take away a convenient notation which programmers familiar with C-like languages take for granted, giving it a special meaning that applies only in limited circumstances.
Basic C or C++ code like for (i = 0; i < LIMIT; i++) would translate into Java as for (i = 0; i < LIMIT; i = i + 1); because it would be inappropriate to use the atomic i++. What's worse, programmers coming from C or other C-like languages to Java would use i++ anyway, resulting in unnecessary use of atomic instructions.
Even at the machine instruction set level, an increment type operation is usually not atomic for performance reasons. In x86, a special instruction "lock prefix" must be used to make the inc instruction atomic: for the same reasons as above. If inc were always atomic, it would never be used when a non-atomic inc is required; programmers and compilers would generate code that loads, adds 1 and stores, because it would be way faster.
In some instruction set architectures, there is no atomic inc or perhaps no inc at all; to do an atomic inc on MIPS, you have to write a software loop which uses the ll and sc: load-linked, and store-conditional. Load-linked reads the word, and store-conditional stores the new value if the word has not changed, or else it fails (which is detected and causes a re-try).
i++ involves two operations :
read the current value of i
increment the value and assign it to i
When two threads perform i++ on the same variable at the same time, they may both get the same current value of i, and then increment and set it to i+1, so you'll get a single incrementation instead of two.
Example :
int i = 5;
Thread 1 : i++;
// reads value 5
Thread 2 : i++;
// reads value 5
Thread 1 : // increments i to 6
Thread 2 : // increments i to 6
// i == 6 instead of 7
Java specification
The important thing is the JLS (Java Language Specification) rather than how various implementations of the JVM may or may not have implemented a certain feature of the language.
The JLS defines the ++ postfix operator in clause 15.14.2 which says i.a. "the value 1 is added to the value of the variable and the sum is stored back into the variable". Nowhere does it mention or hint at multithreading or atomicity.
For multithreading or atomicity, the JLS provides volatile and synchronized. Additionally, there are the Atomic… classes.
Why is i++ not atomic in Java?
Let's break the increment operation into multiple statements:
Thread 1 & 2 :
Fetch value of total from memory
Add 1 to the value
Write back to the memory
If there is no synchronization then let's say Thread one has read the value 3 and incremented it to 4, but has not written it back. At this point, the context switch happens. Thread two reads the value 3, increments it and the context switch happens. Though both threads have incremented the total value, it will still be 4 - race condition.
i++ is a statement which simply involves 3 operations:
Read current value
Write new value
Store new value
These three operations are not meant to be executed in a single step or in other words i++ is not a compound operation. As a result all sorts of things can go wrong when more than one threads are involved in a single but non-compound operation.
Consider the following scenario:
Time 1:
Thread A fetches i
Thread B fetches i
Time 2:
Thread A overwrites i with a new value say -foo-
Thread B overwrites i with a new value say -bar-
Thread B stores -bar- in i
// At this time thread B seems to be more 'active'. Not only does it overwrite
// its local copy of i but also makes it in time to store -bar- back to
// 'main' memory (i)
Time 3:
Thread A attempts to store -foo- in memory effectively overwriting the -bar-
value (in i) which was just stored by thread B in Time 2.
Thread B has nothing to do here. Its work was done by Time 2. However it was
all for nothing as -bar- was eventually overwritten by another thread.
And there you have it. A race condition.
That's why i++ is not atomic. If it was, none of this would have happened and each fetch-update-store would happen atomically. That's exactly what AtomicInteger is for and in your case it would probably fit right in.
P.S.
An excellent book covering all of those issues and then some is this:
Java Concurrency in Practice
In the JVM, an increment involves a read and a write, so it's not atomic.
If the operation i++ would be atomic you wouldn't have the chance to read the value from it. This is exactly what you want to do using i++ (instead of using ++i).
For example look at the following code:
public static void main(final String[] args) {
int i = 0;
System.out.println(i++);
}
In this case we expect the output to be: 0
(because we post increment, e.g. first read, then update)
This is one of the reasons the operation can't be atomic, because you need to read the value (and do something with it) and then update the value.
The other important reason is that doing something atomically usually takes more time because of locking. It would be silly to have all the operations on primitives take a little bit longer for the rare cases when people want to have atomic operations. That is why they've added AtomicInteger and other atomic classes to the language.
There are two steps:
fetch i from memory
set i+1 to i
so it's not atomic operation.
When thread1 executes i++, and thread2 executes i++, the final value of i may be i+1.
In JVM or any VM, the i++ is equivalent to the following:
int temp = i; // 1. read
i = temp + 1; // 2. increment the value then 3. write it back
that is why i++ is non-atomic.
Concurrency (the Thread class and such) is an added feature in v1.0 of Java. i++ was added in the beta before that, and as such is it still more than likely in its (more or less) original implementation.
It is up to the programmer to synchronize variables. Check out Oracle's tutorial on this.
Edit: To clarify, i++ is a well defined procedure that predates Java, and as such the designers of Java decided to keep the original functionality of that procedure.
The ++ operator was defined in B (1969) which predates java and threading by just a tad.
I have a question about using Semaphores in multithreaded Java code.
There are three threads being fired asynchronously. One of them calls zero(), the other calls even(), and the last one calls odd(). "0102" is the correct output.
Semaphore zero = new Semaphore(1);
Semaphore odd = new Semaphore(0);
Semaphore even = new Semaphore(0);
public void zero(IntConsumer printNumber) throws InterruptedException {
for(int i = 0; i < n; i++) {
zero.acquireInterruptibly();
printNumber.accept(0);
if(i % 2 == 0) {
odd.release();
} else {
even.release();
}
}
}
public void even(IntConsumer printNumber) throws InterruptedException {
for (int i = 2; i <= n; i += 2) {
even.acquire();
printNumber.accept(i);
zero.release();
}
}
public void odd(IntConsumer printNumber) throws InterruptedException {
for (int i = 1; i <= n; i += 2) {
odd.acquire();
printNumber.accept(i);
zero.release();
}
}
In the code shown above, the first function that will run is function 'zero' because only that lock is able to be required. Then, the function 'odd' will be able to be called from another thread since it's lock has been released and therefore able to be acquired.
Two questions:
1) Can the same thread that acquired the 'zero' lock reenter the for loop before the lock has been released by the function 'odd'
2) How is the state of the for loop preserved after a thread has been switched out?
Edit: In understanding semaphores a bit more, I know realize that regardless of whether the fact that the thread had acquired the semaphore before, it can not run unless the number of permits available for that sempaphore is greater than 0. Therefore, until the number of permits available is greater than 0, the function will not be able to run until a release of that semaphore occurs so that the number of permits available is greater than 0. The question remains though, how is that state of the for loop preserved so that when I reenter the for loop, I do not start back at the initial 'i' value.
I have an array of threads and I want to start a few of them. The point is that I want to stop the threads with in a for loop.
In the for loop I want to check all threads if they are running or not, and if they are, I want to be asked if I want stop them(dialog box yes/no).
The problem is that the loop doesn't display all the times all three dialog boxes for all those three started thread. Sometime appear 1 dialog box, sometime 3 dialog boxes etc.
So, I do not have the chance to stop all three threads...
public class Main {
public static void main( String[] args )
{
Counter[] arrayOfThreads = new Counter[10];
for( int i = 0; i < arrayOfThreads.length; i++ )
{
arrayOfThreads[i] = new Counter( );
}
arrayOfThreads[3].start( );
arrayOfThreads[5].start( );
arrayOfThreads[2].start( );
for( int i = 0; i < arrayOfThreads.length; i++ )
{
if( arrayOfThreads[i].getState( ) == State.RUNNABLE )
{
int dialogButton = JOptionPane.YES_NO_OPTION;
int dialogResult = JOptionPane.showConfirmDialog( null, "Do you want to stop the theread: " + i, "Warning", dialogButton );
if( dialogResult == JOptionPane.YES_OPTION )
{
arrayOfThreads[i].stopProcessing( );
}
}
}
}
}
class Counter extends Thread
{
volatile boolean processing;
public void run( )
{
int i = 0;
processing = true;
while( processing )
{
System.out.println( " Number: " + i );
i++;
}
System.out.println( "finish" );
}
public void stopProcessing( )
{
processing = false;
}
}
EDIT:
So all what I want is when I press the EXIT button to close the threads and to dispose the frame if all the threads are stoped. I modified the first class to more more clear.
public class Program extends Frame {
public static void main(String[] args) {
Counter[] arrayOfThreads = new Counter[10];
for (int i = 0; i < arrayOfThreads.length; i++) {
arrayOfThreads[i] = new Counter();
}
Program program = new Program(arrayOfThreads);
program.startThreeThreads(1, 4, 5);
}
private Counter[] arrayOfThreads;
private JButton stopThreads;
public Program(Counter[] arrayOfThreads) {
this.arrayOfThreads = arrayOfThreads;
stopThreads = new JButton("STOP THREADS");
closeThreadsWhenExitIsPressed();
setSize(300, 200);
setLayout(new FlowLayout());
add(stopThreads);
setVisible(true);
}
public void closeThreadsWhenExitIsPressed() {
stopThreads.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
stopRunningThreadsMethod();
dispose();
}
});
}
private void startThreeThreads(int first, int second, int third) {
for (int i = 0; i < arrayOfThreads.length; i++) {
if (i == first || i == second || i == third) {
arrayOfThreads[i].start();
continue;
}
}
}
public void stopRunningThreadsMethod() {
for (int i = 0; i < arrayOfThreads.length; i++) {
if (arrayOfThreads[i].isAlive()) {
int dialogButton = JOptionPane.YES_NO_OPTION;
int dialogResult = JOptionPane.showConfirmDialog(null, "Do you want to stop the theread: " + i,
"Warning", dialogButton);
if (dialogResult == JOptionPane.YES_OPTION) {
arrayOfThreads[i].stopProcessing();
}
}
}
}
}
The documentation for getState() is (my emphasis):
Returns the state of this thread. This method is designed for use in
monitoring of the system state, not for synchronization control.
You're trying to use it for synchronization so you're already outside recommendation.
If you look at Thread.State you'll see it isn't always RUNNABLE and I suspect, as is common, System.out is synchronized so although not obvious from your code the thread could be WAITING (on another competing thread to use System.out).
Given all your thread does is hammer output it's probably quite common one or more is waiting. You could even find none show the dialog because as you go round the loop you happen to coincide with that thread waiting!
Check this by reading the state and outputting it!
So first, don't use getState() for synchronization and be aware you don't always know what synchronization is going on 'behind the scenes' in libraries you're using.
The documentation gives leave for the implementer to maybe cut corners in low-level synchronization of getState() and the value may not be 'first class' reliable (synchronized), but regardless don't do things you're told not to even if you don't know why!
The right method is isAlive(). The thread is alive if it has had its start() method called and not yet terminated. Waiting or not, it's alive...
Next problem, is because you set processing=true; in the run() method you could call stopProcessing() before processing has been set true.
There is no guarantee how far (if anywhere) down run() the thread has got when you reach stopProcessing() in the main thread.
I know there's a user interaction (e.g. big delay) but on an overloaded (or single threaded!) machine or a future use case it is possible for processing=true; to be executed after stopProcessing() sets it false. That may lead to 'runaway' processing.
So use volatile boolean processing=true; in the class declaration or set it in the constructor. That guarantees it will be set by the end of the constructor (takes place in the controlling thread) and must be before stopProcessing() is called.
Your application is (of course) a toy but think about when you would stop the threads the user didn't stop.
It's bad practice to just end the JVM without bringing all threads to a safe conclusion.
That doesn't matter in your toy but in real applications you may want to release external resources and (say) flush file buffers rather than let the JVM pull the run out.
That is, finally call stopProcessing() on all the threads in one loop and then join() in a second loop before ending the application.
It's important to use two loops because it makes sure the threads are all stopping concurrently and not one after the other.
I can't emphasise enough why you should end threads properly. People often ignore me and then long into to development have weird glitches that difficult to localise and hard to drive out.
Other considerations:
Consider using interrupt(). It's designed to help terminate threads and does nice things for you like jump them out of sleep and wait conditions (with an Interrupted exception). That will mean they may terminate faster (never slower) than your approach.
Again, not relevant in a toy but valuable in serious application.
Consider sub-classing Runnable instead of Thread. Again your toy is fine and valid but again 'real' applications end up preferring Runnable and using a thread pool of some kind (e.g. ExecutorService). That's clever because on many platforms the overhead of creating and destroying Threads is far larger than a lighter-weight Runnable.
That's the standard advice but I don't think its wisdom is always explained.
The threads probably haven't started by the time you enter the loop in main. Their states are Thread.State.NEW when you check arrayOfThreads[i].getState().
A simple solution would be either to wait some time before executing the loop to make sure the threads are running or to run a while loop over your loop to check the condition more than once.
Both are spotty and inefficient because you don't know exactly when the thread will be up and running. Instead, I would advise implementing a wait-notify mechanism to show a dialogue when the thread is certainly running.
This question already has answers here:
Why is i++ not atomic?
(10 answers)
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 4 years ago.
I wanted to test out multithreading for a project of mine, trying to also develop a solution in case something goes wrong.
So I made this small test:
main
public class main
{
static int addToCounter;
static int addToErrorCounter;
public static void main(String[] args) throws InterruptedException
{
int threads = 10;
Executor exec = new Executor();
for (int i = 0; i < threads; i++)
{
double error = Math.random();
testClass aldo = new testClass();
Thread thread = aldo.getThread(300, error);
exec.execute(thread);
}
while (threads != (addToCounter + addToErrorCounter))
{
System.out.println("Not all threads finished, number of finished threads is: " + (addToCounter + addToErrorCounter));
Thread.sleep(50);
}
System.out.println("Number of Threads that finished correctly: " + addToCounter);
}
}
testClass
import test1.main;
public class testClass
{
public Thread getThread(long time, double error)
{
Thread thread = new Thread()
{
public void run()
{
try
{
Thread.sleep(time);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
if (error > 0.5)
{
main.addToErrorCounter++;
throw new java.lang.Error("HELLO");
}
System.out.println("I DID THIS!");
main.addToCounter++;
}
};
return thread;
}
}
(you'll have to fix the imports, also I use a custom class Executor, although that's only a wrapper for ExecutorService)
The weird behaviour is that sometimes it works properly, and sometimes it doesn't (total terminated thread count is 9, although I can see clearly it printed "I DID THIS!" and the error exactly 10 times).
Any fix?
The Problem might be a racecondition.
the "++" operator is not atomic.
Imageine the following scenario. There are two Threads at the same time. both want to increase a number and finish.
The initial value of the number is 0.
Thread 0 reads the number, knows now it is 0.
Thread 1 reads the number, knows now it is 0.
Thread 0 (who knew it was 0) now writes 1 to the memory.
Thread 1 does not know, that the number has changed, and still believes the number is 0 so he also writes a 1 to the memory.
You need something like a synchronizing mechanisim, something like a lock, or a semaphore or something else.
have a look at this for more information: http://winterbe.com/posts/2015/04/30/java8-concurrency-tutorial-synchronized-locks-examples/
for your example you could use the "synchronized" example from that link.
add a method to your main class looking like this to increment the addToCounter and also to the addToErrorCounterto remove the effects from your error counter:
synchronized AddToError(int e){
addToError += e;
}
synchronized IncCounter(){
addToCounter++;
}
call those methods in your threads in the testclass instead of incrementing them unsynchronized.
My guess is that the postfix operator (main.addToCounter++) is not atomic. This line of code is probably equivalent to something like:
int temp = main.addToCounter;
main.addToCounter = temp + 1;
return temp;
With multiple threads doin this at the same time, two threads could obtain the same value for temp (because both peform the first line in the above pseudo-code before either performs the second), and hence the counter total will be too small once all threads are complete. See Why is i++ not atomic? for more information.
A quick fix in this situation is to make addToCounter an AtomicInteger, then use addToCounter.incrementAndGet() in place of addToCounter++.
I have a question about concurrency, I just wrote a program that runs 2 threads with the following instructions:
Thread 1: increment by 1 the variable "num" till 1'000'000 with loop
Thread 2: same thing but decrementing
at the end I receive an undesired result. And yeah I know that I could synchronize or try to use reentrant locks, but the problem is that I can't understand what's behind all this different undesired results.
I mean the operations I'm using are commutative and hence we don't care about the ordering, so if this doesn't matter we should still obtain 0 which is not the case!
Can someone explain to me what happens behind all the computing, so that I can get a feel and I can recognize this situations immediately?
EDIT:
Since I was just interested in understanding the main concept I thought it wasn't necessary to put the code.
Code:
class MyThread implements Runnable {
int id;
volatile static long num = 0;
MyThread(int id) {
this.id = id;
public void run() {
if (id == 0) {
for (int j = 0; j < 100000; ++j)
num++;}
} else {
for (int j = 0; j < 100000; ++j)
num--;}
After this I create the Threads and run them:
MyThread p = new MyThread(0);
MyThread q = new MyThread(1);
Thread t = new Thread(p);
Thread u = new Thread(q);
t.start();
u.start();
try {
t.join();
u.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
EDIT2:
I understand the concept now, but I would also like to know why declaring the variable as volatile still gives me wrong results?
EDIT3: I thought about it, and I think it's because bad interleaving can still give problems!
If the increment/decrement operation are not atomic, you can end up with this kind of behaviors.
An operation is considered atomic if it appears to the rest of the system to occur instantaneously. (cf wikipedia).
Consider the following case:
Thread 1 reads the value n in the variable x.
Thread 2 reads the value n in the variable x.
Thread 1 increment the value and store it in the variable x, that now evaluate at n+1.
Thread 2 decrements the value and store it in the variable x, that now evaluate at n-1.
But what you wanted was the variable x to still evaluate at n.
I do not know the specific of java primitive but it appears that you could use AtomicInteger or using a synchronized method could solve your issue here.
just mark this field as volatile. By this way you will reach safe access and you will be able to change it in a multi-thread application without using any other synchronization tools.