Reputation: 349
A common way of gaining access to a field is to synchronize the getters and setters. A simple example with an int would look like:
private int foo = 0;
public synchronized int get(){return this.foo;}
public synchronized void set(int bar){ this.foo = bar;}
Now, while this is a safe way of making the access thread safe, it also reveals that only one thread can read foo
at a time.
If many threads where to read foo
very often, and only sometimes update this variable, it would be a big waste. The getter instead could be called by multiple threads simultaneously without any problem.
Are there any established patterns about how to deal with this? Or how would you get around this in the most elegant way?
Upvotes: 3
Views: 1780
Reputation: 636
Take a look at the ReadWriteLock. This interface is what you are looking for, it allows for mutliple readers but only one writer.
An example:
private int foo = 0;
private ReadWriteLock rwLock = /* use some implementation of ReadWriteLock here */;
public int get() {
Lock l = rwLock.readLock();
int result = 0;
l.lock();
try {
result = this.foo;
}
catch(Exception ex) {
// may throw the Exception here
}
finally {
l.unlock();
}
return result;
}
public void set(int bar){
Lock l = rwLock.writeLock();
l.lock();
try {
this.foo = bar;
}
catch(Exception ex) {
// may throw the Exception here
}
finally {
l.unlock();
}
}
Upvotes: 5
Reputation: 8682
For examples as simple as yours, where there is only a single field and no complicated logic in the setter to really demand mutual exclusion, you can just declare the field to be volatile
and remove the synchronized
keywords.
For more complicated stuff, you can use the Cheap Read-Write Lock pattern:
public class CheapReadWriteLockPattern {
// SINGLE-FIELD:
private volatile Object obj;
public Object read() {
return obj;
}
public synchronized void write(Object obj) {
this.obj = obj;
}
// MULTI-FIELD:
private static class Ref {
final Object x;
final Object y;
final Object z;
public Ref(Object x, Object y, Object z) {
this.x = x;
this.y = y;
this.z = z;
}
}
private volatile Ref ref = new Ref(null, null, null);
public Object readX() { return ref.x; }
public Object readY() { return ref.y; }
public Object readZ() { return ref.z; }
public synchronized void writeX(Object x) {
ref = new Ref(x, ref.y, ref.z);
}
public synchronized void writeY(Object y) {
ref = new Ref(ref.x, y, ref.z);
}
public synchronized void writeZ(Object z) {
ref = new Ref(ref.x, ref.y, z);
}
}
Upvotes: 0
Reputation: 41965
If you are just setting and getting the variable: Then you can use volatile
and remove synchronized
method.
If you are doing any operations on the integer like addition you should use AtomicInteger
.
EDIT:
If there is a scenario that the field is read multiple times and updated few times then there is a pattern called IMMUTABLE. This is one of the way to achieve thread safety.
class ImmutableClass{
private final int a;
public ImmutableClass(int a) {
this.a = a;
}
public int getA(){
return a;
}
/*
* No setter methods making it immutable and Thread safe
*/
}
For more detailed knowledge on Immutability, Java Concurrency In practice is the best resource I would suggest you to read.
For more advanced ways: There is a Read/Write lock
Upvotes: 3