Java IllegalStateMonitorException while holding the lock - java

I have written a class in java that implements a double buffer.
The class has two methods to write into the two buffers and a method to clear them.
Then I have three thread: one that writes on the first buffer, another that writes on the second buffer and a third one that clears the buffers.
Here, I paste (a piece of) the code that causes the problem (I know that it is not correct, but i've simplified it for debugging purposes):
public void addAlpha(int toAdd){
synchronized (alphaCount) {
while(alphaCount >= alpha.length){
try {
alphaCount.wait();
} catch (InterruptedException e) {
}
}
alpha[alphaCount] = toAdd;
alphaCount++;
}
}
And here the piece in which i call the notifyAll():
public void clear(){
synchronized (alphaCount) {
alphaCount = 0;
alphaCount.notifyAll();
}
}
As you can see, in the addAlpha method, I get the lock on alphaCount, test the condition and then wait on the alphaCount object.
In the clear method, i get the lock on alphaCount and I call notifyAll() on it.
At runtime, I get the IllegalStateMonitorException...
But I really don't know where the error is: I checked the documentation and more than one forum, without any luck...
Thanks for your time and your attention,
Rick.

As a rule, you should make field used as a lock final otherwise you can get bugs like this. IMHO You should make as many field final as you can. ;)
synchronized (alphaCount) { // alphaCount == 1 which is locked.
alphaCount = 0; // alphaCount == 0 which is not locked.
alphaCount.notifyAll(); // fails.
}
Additionally I wouldn't recommend using Integer or String or any wrapper type for a lock. As there are many confusing and surprising consequences. e.g.
Integer i1 = 127;
Integer i2 = 127; // same object due to the auto-boxing cache.
i1 == i2;
Integer i1 = 128;
Integer i2 = 128; // not the same object.
i1 != i2; // may or may not be the same object depending on the cache size.
Another problem is that you could get a deadlock with a completely unrelated library which also happens to be using integer as a lock.
The solution is to use a dedicated lock object.
private final Object alphaCountLock = new Object();
private int alphaCount = 0; // don't use an object when a primitive will do.
synchronized (alphaCountLock ) {
alphaCount = 0;
alphaCountLock .notifyAll();
}

Related

Broken singleton without volatile example

I know, that in theory, to implement a correct singleton, in addition to double checked locking and synchronized we should make an instance field volatile.
But in real life I cannot get an example, that would expose the problem. Maybe there is a JVM flag that would disable some optimisation, or allow runtime to do such code permutation?
Here is the code, that, as I understand, should print to console from time to time, but it doesn't:
class Data {
int i;
Data() {
i = Math.abs(new Random().nextInt()) + 1; // Just not 0
}
}
class Keeper {
private Data data;
Data getData() {
if (data == null)
synchronized (this) {
if (data == null)
data = new Data();
}
return data;
}
}
#Test
void foo() throws InterruptedException {
Keeper[] sharedInstance = new Keeper[]{new Keeper()};
Thread t1 = new Thread(() -> {
while (true)
sharedInstance[0] = new Keeper();
});
t1.start();
final Thread t2 = new Thread(() -> {
while (true)
if (sharedInstance[0].getData().i == 0)
System.out.println("GOT IT!!"); // This actually does not happen
});
t2.start();
t1.join();
}
Could someone provide a code, that clearly demonstrates described theoretical lack of volatile problem?
Very good article about it
https://shipilev.net/blog/2014/safe-public-construction/
You can find examples in the end.
And be aware about
x86 is Total Store Order hardware, meaning the stores are visible for all processors in some total order. That is, if compiler actually presented the program stores in the same order to hardware, we may be reasonably sure the initializing stores of the instance fields would be visible before seeing the reference to the object itself. Even if your hardware is total-store-ordered, you can not be sure the compiler would not reorder within the allowed memory model spec. If you turn off -XX:+StressGCM -XX:+StressLCM in this experiment, all cases would appear correct since the compiler did not reorder much.

Why a synchronized getter work like a volatile read?

This program does not terminate!
public class Main extends Thread {
private int i = 0;
private int getI() {return i; }
private void setI(int j) {i = j; }
public static void main(String[] args) throws InterruptedException {
Main main = new Main();
main.start();
Thread.sleep(1000);
main.setI(10);
}
public void run() {
System.out.println("Awaiting...");
while (getI() == 0) ;
System.out.println("Done!");
}
}
I understand this happens because the CPU core running the Awaiting loop always sees the cached copy of i and misses the update.
I also understand that if I make volatileprivate int i = 0; then the while (getI()... will behave[1] as if every time it is consulting the main memory - so it will see the updated value and my program will terminate.
My question is: If I make
synchronized private int getI() {return i; }
It surprisingly works!! The program terminates.
I understand that synchronized is used in preventing two different threads from simultaneously entering a method - but here is only one thread that ever enters getI(). So what sorcery is this?
Edit 1
This (synchronization) guarantees that changes to the state of the object are visible to all threads
So rather than directly having the private state field i, I made following changes:
In place of private int i = 0; I did private Data data = new Data();, i = j changed to data.i = j and return i changed to return data.i
Now the getI and setI methods are not doing anything to the state of the object in which they are defined (and may be synchronized). Even now using the synchronized keyword is causing the program to terminate! The fun is in knowing that the object whose state is actually changing (Data) has no synchronization or anything built into it. Then why?
[1] It will probably just behave as that, what actually, really happens is unclear to me
It is just coincidence or platform dependent or specific JVM dependent, it is not guaranteed by JLS. So, do not depend on it.

Is an assignment inside ConcurrentHashMap.computeIfAbsent threadsafe?

Consider the following implementation of some kind of fixed size cache, that allows lookup by an integer handle:
static class HandleCache {
private final AtomicInteger counter = new AtomicInteger();
private final Map<Data, Integer> handles = new ConcurrentHashMap<>();
private final Data[] array = new Data[100_000];
int getHandle(Data data) {
return handles.computeIfAbsent(data, k -> {
int i = counter.getAndIncrement();
if (i >= array.length) {
throw new IllegalStateException("array overflow");
}
array[i] = data;
return i;
});
}
Data getData(int handle) {
return array[handle];
}
}
There is an array store inside the compute function, which is not synchronized in any way. Would it be allowed by the java memory model for other threads to read a null value from this array later on?
PS: Would the outcome change if the id returned from getHandle was stored in a final field and only accessed through this field from other threads?
The read access isn't thread safe. You could make it thread safe indirectly however it's likely to be brittle. I would implemented it in a much simpler way and only optimise it later should it prove to a performance problem. e.g. because you see it in a profiler for a realistic test.
static class HandleCache {
private final Map<Data, Integer> handles = new HashMap<>();
private final List<Data> dataByIndex = new ArrayList<>();
synchronized int getHandle(Data data) {
Integer id = handles.get(data);
if (id == null) {
id = handles.size();
handles.put(data, id);
dataByIndex.add(id);
}
return id;
}
synchronized Data getData(int handle) {
return dataByIndex.get(handle);
}
}
Assuming that you determine the index for the array read from the value of counter than yes - you may get a null read
The simplest example (there are others) is a follows:
T1 calls getHandle(data) and is suspended just after int i = counter.getAndIncrement();
T2 calls handles[counter.get()] and reads null.
You should be able to easily verify this with a strategically placed sleep and two threads.
From the documentation of ConcurrentHashMap#computeIfAbsent:
The entire method invocation is performed atomically, so the function is applied at most once per key. Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this map.
The documentation's reference to blocking refers only to update operations on the Map, so if any other thread attempts to access array directly (rather than through an update operation on the Map), there can be race conditions and null can be read.

synchronize max value while one thread add items and one thread removes items

I'm implementing a program with ArrayList with Objects called Bicycle in it.
I maintain a variable to save the max Bicycle (measured by its id) and a variable to save the max Bicycle index in the array.
I have implented 2 functions - addBicycle and removeMax and they are synchornized.
I'm worried about what might happen when one thread is in addBicycle and other thread is in removeMax - one might add new bicycle which will be the maximum and the second thread will remove accidently older value which is no longer a maximum.
Is there a way to prevent it? a way to forbid that one thread will be at the add function and the other at the remove function, at the same time?
Thanks
edit: code -
public BicycleDataStructure() {
list = new ArrayList<T>();
maxBicycle = null;
maxBicycleIndex = 0;
}
public synchronized void addBicycle(T bToAdd) {
if (list.size() == 0) {
list.add(bToAdd);
maxBicycle = bToAdd;
maxBicycleIndex = 0;
} else {
for (int i = 0; i < list.size(); i++) {
//checks to add in the right position in the list
list.add(i, bToAdd); }
}
}
public synchronized Bicycle removeMaxBicycle() {
if (list.isEmpty()){
return null;
}
list.remove(maxBicycleIndex);
if (!list.isEmpty()) {
maxBicycle = collection.get(maxBicycleIndex- 1);
maxBicycleIndex-= 1;
}
}
You are using synchronized method on same object lock so it is safe due to below reason
It is not possible for two invocations of synchronized methods on the
same object to interleave. When one thread is executing a synchronized
method for an object, all other threads that invoke synchronized
methods for the same object block (suspend execution) until the first
thread is done with the object.
Second, when a synchronized method exits, it automatically establishes
a happens-before relationship with any subsequent invocation of a
synchronized method for the same object. This guarantees that changes
to the state of the object are visible to all threads.
With your current implementation, it will not work as you expect. The synchronized keyword just prevent that two threads cannot access that block of code at the same time. However what you've got is two different methods and the situation you described might happen.
When you need to synchronize two methods, consider using semaphore:
private static final int MAX_AVAILABLE = 1;
private final Semaphore semaphore = new Semaphore(MAX_AVAILABLE, true);
public Bicycle removeMaxBicycle(){
semaphore.acquire();
//do your critical stuff
semaphore.release();
}
public void addBicycle(T bToAdd) {
semaphore.acquire();
//do your critical stuff
semaphore.release();
}
If you have any doubt in how to use Semaphore in Java, checkout this link: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html

How to solve race condition of two writers using immutable objects

I was thinking about how to solve race condition between two threads which tries to write to the same variable using immutable objects and without helping any keywords such as synchronize(lock)/volatile in java.
But I couldn't figure it out, is it possible to solve this problem with such solution at all?
public class Test {
private static IAmSoImmutable iAmSoImmutable;
private static final Runnable increment1000Times = () -> {
for (int i = 0; i < 1000; i++) {
iAmSoImmutable.increment();
}
};
public static void main(String... args) throws Exception {
for (int i = 0; i < 10; i++) {
iAmSoImmutable = new IAmSoImmutable(0);
Thread t1 = new Thread(increment1000Times);
Thread t2 = new Thread(increment1000Times);
t1.start();
t2.start();
t1.join();
t2.join();
// Prints a different result every time -- why? :
System.out.println(iAmSoImmutable.value);
}
}
public static class IAmSoImmutable {
private int value;
public IAmSoImmutable(int value) {
this.value = value;
}
public IAmSoImmutable increment() {
return new IAmSoImmutable(++value);
}
}
If you run this code you'll get different answers every time, which mean a race condition is happening.
You can not solve race condition without using any of existence synchronisation (or volatile) techniques. That what they were designed for. If it would be possible there would be no need of them.
More particularly your code seems to be broken. This method:
public IAmSoImmutable increment() {
return new IAmSoImmutable(++value);
}
is nonsense for two reasons:
1) It makes broken immutability of class, because it changes object's variable value.
2) Its result - new instance of class IAmSoImmutable - is never used.
The fundamental problem here is that you've misunderstood what "immutability" means.
"Immutability" means — no writes. Values are created, but are never modified.
Immutability ensures that there are no race conditions, because race conditions are always caused by writes: either two threads performing writes that aren't consistent with each other, or one thread performing writes and another thread performing reads that give inconsistent results, or similar.
(Caveat: even an immutable object is effectively mutable during construction — Java creates the object, then populates its fields — so in addition to being immutable in general, you need to use the final keyword appropriately and take care with what you do in the constructor. But, those are minor details.)
With that understanding, we can go back to your initial sentence:
I was thinking about how to solve race condition between two threads which tries to write to the same variable using immutable objects and without helping any keywords such as synchronize(lock)/volatile in java.
The problem here is that you actually aren't using immutable objects: your entire goal is to perform writes, and the entire concept of immutability is that no writes happen. These are not compatible.
That said, immutability certainly has its place. You can have immutable IAmSoImmutable objects, with the only writes being that you swap these objects out for each other. That helps simplify the problem, by reducing the scope of writes that you have to worry about: there's only one kind of write. But even that one kind of write will require synchronization.
The best approach here is probably to use an AtomicReference<IAmSoImmutable>. This provides a non-blocking way to swap out your IAmSoImmutable-s, while guaranteeing that no write gets silently dropped.
(In fact, in the special case that your value is just an integer, the JDK provides AtomicInteger that handles the necessary compare-and-swap loops and so on for threadsafe incrementation.)
Even if the problems are resolved by :
Avoiding the change of IAmSoImmutable.value
Reassigning the new object created within increment() back into the iAmSoImmutable reference.
There still are pieces of your code that are not atomic and that needs a sort of synchronization.
A solution would be to use a synchronized method of course
public synchronized static void increment() {
iAmSoImmutable = iAmSoImmutable.increment();
}
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
increment();
}
});

Categories