I'm working with a couple of classes which I need to use with multithreading. Since the access pattern is the same but they use different data structures, I extracted the access pattern to a superclass and left use its methods to manage the access, while the subclassess simply manage the data structure. It worked fine as long as I simply used synchronized
blocks (and even single wait
s), but when I tried to introduce notify
or notifyAll
instructions it started throwing IllegalMonitorStateException
s.
My superclass:
public abstract class SyncObject {
protected Integer readLock;
protected Boolean writeLock;
public SyncObject(){
this.readLock = 0;
this.writeLock = false;
}
protected void acquireReadLock(){
boolean hasBeenInterrupted = false;
synchronized (this.writeLock){
while(this.writeLock)
try {
this.writeLock.wait();
} catch (InterruptedException e) {
//We can't leave the locks in a non-consistent state, so the interruption is swallowed
//Once the lock have been set the interruption flag is set again to true, in case we need
// it later
hasBeenInterrupted = true;
}
synchronized (this.readLock){
this.readLock++;
}
}
if(hasBeenInterrupted){
Thread.currentThread().interrupt();
}
}
protected void releaseReadLock(){
synchronized (this.readLock){
this.readLock--;
}
}
protected void acquireWriteLock(){
boolean hasBeenInterrupted = false;
synchronized (this.readLock){
synchronized (this.writeLock){
while(this.readLock > 0)
try {
this.readLock.wait();
} catch (InterruptedException e) {
//See above
hasBeenInterrupted = true;
}
while(this.writeLock)
try {
this.writeLock.wait();
} catch(InterruptedException e) {
//See above
hasBeenInterrupted = true;
}
this.writeLock = true;
}
}
if(hasBeenInterrupted){
Thread.currentThread().interrupt();
}
}
protected void releaseWriteLock(){
synchronized (this.writeLock){
this.writeLock = false;
}
}
}
My typical use of this is:
public class MySyncClass extends SyncObject{
private String myData;
public MySyncClass(){
super();
this.myData = "foo";
}
public String read(){
super.acquireReadLock();
String s = this.myData;
super.releaseReadLock();
return s;
}
public void write(String s){
this.acquireWriteLock();
this.myData = s;
this.releaseWriteLock();
}
}
If I copy the superclass' methods in my classess it works fine, but is there a way to manage everything from the superclass (thus avoiding to copy the same code in multiple classes)?