I have an object that is accessed from multiple threads. I want to implement it so that in order to access its setters and getters, the caller must first explicitly lock it before and then unlock it after finishing. I've though about using synchronized methods but it doesn't seem very straight-forward compared to java's more explicit locking APIs. This is my current stubbed implementation using ReentrantLock.
public class Data {
private ReentrantLock lock;
private int IntValue;
public Data() {
this.IntValue = 0;
this.lock = new ReentrantLock();
}
public void Lock() {
lock.lock();
}
public void Unlock() {
if (!lock.isLocked()) {
return;
}
//only the thread owning the lock can proceed to unlock
lock.lock();
int lockCount = lock.getHoldCount();
for (int i = 0; i < lockCount; i++) {
lock.unlock();
}
}
public void SetVal(int val) {
if (!lock.isLocked()) {
return;
}
lock.lock();
this.IntValue = val;
}
}
So if a thread wants to call SetVal(int val), it would first have to call Lock() and then call Unlock() when it's done. I've placed isLocked() checks in its setter/getter methods to enforce this rule. And I've added an additional lock call in unlock to make sure only the thread owning the lock can proceed to unlock (an unique feature of ReentrackLock). The object's setters/getters could be called many times before its Unlock() method is called. So in the Unlock() method I have to iterate through its HoldCount and unlock for each count.
I'm wondering if there is a more efficient and idiomatic way of achieving this?
If you are only using int value then can go for AtomicInteger
or make all your method synchronized that you want to prevent from race condition.
or if you want to support both synchronized and normal then you can pit a wrapper like collections.SynchronizedSet.Hope this will help.
You are running into the wrong direction with your approach. OOP paradigms state that all data should be kept and managed internally, what you do however is to externalize that control over the internal data by giving it to the caller.
A good design would try to hide the fact that locking is even necessary and do it internally to free the caller from such tasks. Especially because if you transfer the responsibility of proper locking to the caller, then every single caller could be a potential thread issue. If you lock internally however, there is only a single source of potential bugs, so if you encounter an issue you know where to look.
This is how you would do it properly regarding the OOP paradigm:
public class Data {
// protected so it is accessible to derived classes
// final so the lock object cannot be (accidentally) reassigned
// Lock (base class) so it is easier to change the implementation later
protected final Lock lock;
// clear naming
private int value;
public Data() {
// value is automatically initialized with 0
this.lock = new ReentrantLock();
}
// by convention the setter for ... is set...
public void setValue(final int value) {
this.lock.lock();
// absolutely use try/finally here, to ensure it is unlocked in all cases
try {
this.value = value;
} finally {
this.lock.unlock();
}
}
// by convention the getter for ... is get...
public int getValue() {
this.lock.lock();
try {
return this.value;
} finally {
this.lock.unlock();
}
}
}
Related
I have this code:
private volatile boolean immortal;
private Object lock = new Object();
public void set(boolean immortal) {
this.immortal = immortal;
}
public void kill() {
// .... contains some other code.
synchronized(lock) {
if (!immortal) {
for (int i = 0; i < numThreads; i++) {
runnableList.add(POISON_PILL);
}
}
}
}
My use case is that I would like the if statement in the kill method to run to completion before immortal value is changed. Is there a better way of doing this without locking on an object?
I mean what is the best way to synchronize a block only if the value of a boolean variable is false and not allow the boolean value to be changed till it runs to completion? Can I achieve this using AtomicBoolean?
A neat way to do this could be to declare your runnableList as a synchronized list:
// where T is whatever type it needs to be
List<T> runnableList = Collections.synchronizedList(new ArrayList<>());
Then you could add to it without explicit synchronization:
if (!immortal) {
runnableList.addAll(Collections.nCopies(numThreads, POISON_PILL));
}
This works because a single call to addAll is atomic.
This isn't doing it without synchronization, though, it's just internal to the list.
With this said, it's hard to recommend a "better" solution because it's not clear what the requirements are. Synchronization (etc) is used to preserve the invariants of your object when operated on by multiple threads.
For example, why do you need immortal to remain unchanged while you add things to runnableList? How else do you access immortal and runnableList? etc
Use two locks:
private boolean immortal;
private final Object killMonitor = new Object();
private final Object flagMonitor = new Object();
public void set(boolean immortal) {
synchronized (flagMonitor) {
this.immortal = immortal;
}
}
public void kill() {
// ...
synchronized (flagMonitor) {
if (!immortal) {
synchronized (killMonitor) {
runnableList.addAll(Collections.nCopies(numThreads, POISON_PILL));
}
}
}
}
Consider the following code implementing double check locking using the synchronized keyword in JAVA 8:
private static void redoHeavyInitialisation() {
if (needToReinitialise()) {
synchronized (MyClass.class) {
if (needToReinitialise()) {
doHeavyInitialisation();
}
}
}
}
The reason double check locking is used is because the initialisation is heavy (hence lazy) AND it can happen more than once (hence singleton pattern can not be used, correct me if I am wrong).
Anyway, first, how do you convert the code above to use Lock from the JAVA concurrent package instead of using synchronized keyword?
Only after that AND optionally, feel free to comment on using Lock or synchronized keyword which one is better.
Remember, this question is not about Lock vs synchronized comparison. Answer attempts without answering the code conversion part will not be picked as accepted answer.
Transformation of synchronized blocks to the equivalent block using ReentrantLock is pretty rote.
First you create a lock with the same or similar scope and lifetime as the object you were locking on. Here you are locking on MyClass.class, hence a static lock, so you can map this to a static lock in MyClass, such as MyClass.initLock.
Then just replace each:
synchronized (object) {
with
lock.lock();
try {
and each associated closing brace with
} finally {
lock.unlock();
}
Putting it all together you have:
private final static ReentrantLock initLock = new ReentrantLock();
private static void redoHeavyInitialisation() {
if (needToReinitialise()) {
MyClass.initLock.lock();
try {
if (needToReinitialise()) {
doHeavyInitialisation();
}
} finally {
MyClass.initLock.unlock();
}
}
}
Performance-wise there is little daylight between the approaches. They essentially have the same semantics and usually use similar underlying mechanisms. In the past, there have been performance differences - sometimes optimizations have gone in that affect one or the other, so on some JVMs you can find a difference, but the whole point of double checked locking is to avoid taking the lock anyway, so just do what's simplest. You only get the lock for a very small transitory period while the needToReinitialise() method is running, so the locking cost won't have any ongoing impact.
Consider the following code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HeavyInitializer {
static final Logger logger = LoggerFactory.getLogger(HeavyInitializer.class);
static HeavyInitializer singleton;
public static synchronized HeavyInitializer getInstance() {
if (singleton==null) {
singleton = new HeavyInitializer();
}
return singleton;
}
boolean initialized;
private HeavyInitializer() {
initialized = false;
}
public synchronized void initialize() {
if (!initialized) {
heavyStuffDoneHere();
}
}
public synchronized void reInitilize() {
if (needToReinitialise()) {
heavyStuffDoneHere();
}
}
private void heavyStuffDoneHere() {
initialized = true;
}
private boolean needToReinitialise() {
if (!initialized)
return false;
boolean ret = false;
//Do your check here... and set ret
return ret;
}
}
From Oracle's doc:
... then making these methods synchronized has two effects:
First, 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.
Trying to use Lock would be trying to reimplement the synchronized block. Not necessary.
Singleton Double checks the lock and prevents singleton object to break using serialization.
package pattern.core.java;
import java.io.Serializable;
public class Singleton extends Object implements Serializable {
private static final long serialVersionUID = 1L;
private static Singleton sg;
private Singleton() {
}
public static Singleton getSingletonObj() {
if (sg == null) {
synchronized (sg) {
if (sg == null) {
sg = new Singleton();
}
}
}
return sg;
}
/*
* this method ensures that new object will not be created for singleton
* class using serialization and deserialization
*/
protected Object readResolve() {
return sg;
}
/*
* #Override protected Object clone() throws CloneNotSupportedException {
* throw new CloneNotSupportedException(); }
*/
#Override
protected Object clone() throws CloneNotSupportedException {
return sg;
}
}
Say I have a class with 2 instance variables and the following methods (simplified for this question):
private final Object lock = new Object();
private boolean running;
public MyClass() {
synchronized(lock) {
running = false;
}
}
public void methodA() {
synchronized(lock) {
running = true;
}
}
public void methodB() {
synchronized(lock) {
if (!running) {
return;
}
}
}
I was looking at this code, and after reading about AtomicBoolean, I thought that one might fit here, especially after looking at the MyClass constructor and methodA. I wasn't too sure about methodB though.
Assuming these methods could get called by multiple threads, would the following be thread-safe?:
private AtomicBoolean running;
public MyClass() {
running = new AtomicBoolean(false);
}
public void methodA() {
running.set(true);
}
public void methodB() {
if (!running.get()) {
return;
}
}
Will running.get() be guaranteed to see an update via running.set(true) or running.set(false) from another thread?
In your example, a simple volatile boolean would be enough, since you only seem to be doing atomic operations. AtomicBoolean is useful if you need the methods such as compareAndSet.
So in answer to your question, yes, when using a volatile boolean or an AtomicBoolean, other threads will see the updates to the variable.
Generally speaking these code blocks are not equal for methodB, because reading volatile variable does not create synchronization order.
Imagine you have some other field int x = 42 in your class, that is updated in methodB:
public void methodB() {
if (!running.get()) {
return;
}
if (x < 50) x++; // just example
}
Then you have several threads that call methodB:
when using synchronized keyword, updates are safe and visible to all threads.
when using AtomicBoolean/volatile visibility is broken
If there is no such case with variable updates and the task is just to guarantee visibility between methodA - methodB sequence, then it's OK - AtomicBoolean is enough for that.
Yes. From the Javadoc of AtomicBoolean:
A {#code boolean} value that may be updated atomically.
This means that any update to AtomicBoolean is indivisible. So, I would consider such use of AtomicBoolean to be thread safe.
You should still consider making the declaration of AtomicBoolean final:
private final AtomicBoolean running;
I am writing a utility class to implement the behavior of a stopwatch. One important feature of this class is that it is designed to be thread-safe. I use a private final field called lock to synchronize on. Two of the methods in the class are called reset and start, which reset the stopwatch and start it, respectively. They are implemented as:
public void reset() {
synchronized (lock) {
beginTime = 0;
lapIndex = 0;
}
}
public void start() {
synchronized (lock) {
if (beginTime == 0) {
beginTime = System.nanoTime();
laps[lapIndex++] = beginTime;
}
}
}
Recently, I had the idea of adding an additional convenience method called restart, which would reset and the start the stopwatch. I want this to behave like an atomic operation, so my idea was to implement it as:
public void restart() {
synchronized(lock) {
reset();
start();
}
}
However, the reset and start methods already synchronize on lock, so invoking restart would synchronize on the same object two times. Could any problems arise from that? Is the behavior of synchronizing on the same object multiple times well-defined? Is it necessary? I have ran the code as it seems to work fine, but I fear I could be missing some subtleties as is common with multithreading.
There's no problem with synchronizing twice. The thread already owns the monitor so the extra synchronization doesn't really do much. This will be necessary, otherwise your restart() method might be interrupted by another thread between calls to reset() and start().
A way of avoiding the double synchronization is to have restart(), reset(), and start() synchronize and then delegate to non-synchronized internal methods.
public void reset() {
synchronized (lock) {
_reset();
}
}
public void start() {
synchronized (lock) {
_start();
}
}
public void restart() {
synchronized(lock) {
_reset();
_start();
}
}
private void _reset() {
beginTime = 0;
lapIndex = 0;
}
private void _start() {
if (beginTime == 0) {
beginTime = System.nanoTime();
laps[lapIndex++] = beginTime;
}
}
From section 14.19 on synchronized statements of the Java language specification:
The locks acquired by synchronized statements are the same as the locks that are acquired implicitly by synchronized methods (ยง8.4.3.6). A single thread may acquire a lock more than once.
Also from the JLS:
A thread t may lock a particular monitor multiple times; each unlock reverses the effect of one lock operation.
Therefore, this shouldn't be a problem.
I need to lock two objects in a functionality and the current code looke like this;
Object obj1 = ...//get from somewhere
Object obj2 = ...//get from somewhere
synchronized(obj1){
...//blah
synchronized(obj2){
...//blah
}
}
As you can see this is a plain and straight recipe for deadlocks if another thread runs this piece of code with obj1 and two reversed.
Is there a way to avoid this situation using concurrency-utils locks?
I was contemplating maintaining a map of objects and their locks and verifying if they were available to take, but can't seem to come up with a clean way which will predict the lock order.
Although you preserve locking order, if obj1 is switched with obj2 you'll run into deadlock.
You must look for another solution to avoid this cases: lock ordering + optional tie breaking lock
int fromHash = System.identityHashCode(obj1);
int toHash = System.identityHashCode(obj2);
if (fromHash < toHash) {
synchronized (obj1) {
synchronized (obj2) {
........
}
}
} else if (fromHash > toHash) {
synchronized (obj2) {
synchronized (obj1) {
........
}
}
} else {
synchronized (TIE_LOCK) {
synchronized (fromAcct) {
synchronized (toAcct) {
...
}
}
}
Depending on what you are doing you may be able to take what you want from the first locked object and use that information to process the second locked object. e.g.
instead of
synchronized(list1) {
for(String s : list1) {
synchronized(list2) {
// do something with both lists.
}
}
}
do this
List<String> listCopy;
synchronized(list1) {
listCopy = new ArrayList<String>(list1);
}
synchornized(list2) {
// do something with liastCopy and list2
}
You can see you only have lock at a time so you won't get a deadlock.
You need to consistently lock in the order of obj1 and then obj2. If you never violate this order, you won't have deadlocks.
Essentially what you have is the dining philospher's problem.
https://en.wikipedia.org/wiki/Dining_philosophers_problem
Ovidiu Lupas's answer is similar to Dijkstra's Resource Heirarchy solution, but there are 3 more solutions, explained on the wiki page
This is what the arbitrator solution looks like. If all of the objects which you're operating from inherit from the same type, you could use static class variables to implement the arbitrators on the class of objects.
import java.util.concurrent.locks.Lock;
public void init()
{
Lock arbitrator = new Lock();
}
public void meth1()
{
arbitrator.lock();
synchronized (obj1) {
synchronized (obj2) {
arbitrator.unlock();
// Do Stuff
}
}
}
public void meth2()
{
arbitrator.lock();
synchronized (obj2) {
synchronized (obj1) {
arbitrator.unlock();
// Do Stuff
}
}
}
The Chandy/Misra solution requires a lot of message passing so I'm not going to implement it, but wikipedia has a pretty good explaination
You can solve it in other way I suppose.
class Obj implements Comparable<Obj> {
// basically your original class + compare(Obj other) implementation
}
class ObjLock implements Lock, Comparable<ObjLock> {
private final Lock lock;
private final Obj obj; // your original object
ObjLock(Obj obj) {
this.obj = obj;
this.lock = new ReentrantLock();
}
#Override
public int compare(ObjLock other) {
return this.obj.compare(other.obj); // ObjLock comparison based on Obj comparison
}
// + reimplement Lock methods with this.lock invocations
}
Then do
class ObjLocksGroup {
private final List<ObjLock> objLocks;
ObjLocksGroup(ObjLock... objLocks) {
this.objLocks = stream(objLocks)
.sorted() // due to ObjLock implements Comparable and sorting you are sure that order of ObjLock... will always be the same
.collect(toList));
}
void lock() {
this.objLocks.forEach(ObjLock::lock);
}
void unlock() {
this.objLocks.forEach(ObjLock::unlock);
}
}
And use it as you want:
ObjLocksGroup locks = new ObjLocksGroup(obj1, obj2) // the same as obj2, obj1, order does not matter anymore.
locks.lock();
locks.unlock();