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();
Related
I'm trying to create thread safe queue with unique elements. I see no vulnerabilities but not sure still is this realisation thread safe or not? get(), add(), toArray() methods do everything under lock, toString() and equals() use toArray() in order to get main array copy and work independently with copy without locks.
public class SafeQueue<T> {
private final Object[] queue;
private final HashSet<T> content;
private final Lock lock;
private int size;
public SafeQueue() {
queue = new Object[100];
content = new HashSet<>(100);
lock = new ReentrantLock();
}
public boolean add(T el) {
Objects.requireNonNull(el);
final Lock lock = this.lock;
lock.lock();
try {
//some logic
} finally {
lock.unlock();
}
return true;
}
public T get() {
final Lock lock = this.lock;
lock.lock();
try {
T el = (T) queue[0];
if (el != null) {
//some shift logic
content.remove(el);
}
return el;
} finally {
lock.unlock();
}
}
public Object[] toArray() {
final Lock lock = this.lock;
lock.lock();
try {
return Arrays.copyOf(this.queue, size);
} finally {
lock.unlock();
}
}
#Override
public boolean equals(Object o) {
Object[] eqQueue = ((SafeQueue<?>) o).toArray();
Object[] curQueue = toArray();
//some comparison logic with eqQueue and curQueue
return equal;
}
#Override
public String toString() {
Object[] curQueue = toArray();
StringBuilder sb = new StringBuilder();
sb.append('[');
//some logic with curQueue
return sb.toString();
}
}
You might want to ask, what does it mean for the equals method to be thread safe? Consider this:
SafeQueue<T> qa = ...;
SafeQueue<T> qb = ...;
...
if (qa.equals(qb)) {
handleEqualsCase();
}
If you had any reason to worry about the thread-safety of the equals() method, that could only be because other threads potentially could modify either queue when equals() is called.
But, by the time handleEqualsCase() is called, those other threads still could be running, and now, neither qa nor qb is locked. There is no guarantee that the two queues still will be equal when handleEqualsCase() is called. But, if they're not equal, that must be a Bad Thing, right? Otherwise, why would you have bothered to test for equality in the first place?
Here's one way around that problem. Instead of writing a traditional equals() method, write something like this instead:
private static
boolean unsynchronizedEqualityTest(SafeQueue<T> qa, SafeQueue<T> qb) {
...
}
public static
void doIfEqual(SafeQueue<T> qa, SafeQueue<T> qb, Runnable handler) {
qa.lock.lock();
qb.lock.lock();
try {
if (unsynchronizedEqualityTest(qa, qb)) {
handler.run();
}
} finally {
qb.lock.unlock();
qa.lock.unlock();
}
}
Now, when the client-supplied handler is invoked, it's guaranteed that the two queues still will be equal because they're both still locked.
But BEWARE! There's potential for a deadlock if one thread calls doIfEqual(qa,qb,...) and another thread calls doIfEqual(qb,qa,...). I'll leave it to you to figure out how to prevent that deadlock from happening.
Yes, your implementation is thread safe.
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));
}
}
}
}
Is instantiating an instance of SynchroClass as defined below and calling sCMethod going to cause a deadlock when the second sCMethod tries to get a lock on lockObject?
SO suggests I might mean something like Re-entrancy in Java saves us from a deadlock situation in this code sample.. How, why?, which seems to suggest that it is not a deadlock as the same object already has the lock ownership, but that talks about synchronized methods, so is at least a little different.
class SynchroClass {
static Object lockObject = new Object();
private boolean otherCondition = true;
public boolean sCMethod(boolean condition) {
synchronized(lockObject) {
if(condition) {
// some code
} else if(otherCondition) {
// some code
sCMethod(false);
// some code
} else {
// some code
}
return true;
}
}
}
In my class I have code like:
int counter1;
int counter2;
public void method1(){
if (counter1>0) {
...........do something
if (counter2>0) {
....do something else
}
}
public void method2() {
counter1=0;
counter2=0;
}
I need that both counters set together. I am afraid that OS can to method1 can be invoked after setting counter1 only. Does it possible?
Thanks.
Either use the synchronized keyword as the other answer suggest or use the ReentrantReadWriteLock if you have more reads than writes to the counter, for better performance. You can read about the lock here http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html
private int counter1;
private int counter2;
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
public void method1(){
r.lock();
try {
if (counter1>0) {
...........do something
if (counter2>0) {
....do something else
}
} finally { r.unlock(); }
}
public void method2() {
w.lock();
try {
counter1=0;
counter2=0;
} finally { w.unlock(); }
}
Sure, just use the synchronized keyword:
private final Object LOCK = new Object();
int counter1;
int counter2;
public void method1() {
synchronized(LOCK) {
if (counter1>0) {
...........do something
if (counter2>0) {
....do something else
}
}
}
public void method2() {
synchronized(LOCK) {
counter1=0;
counter2=0;
}
}
Some tips:
Use a private object for synchronization rather than marking a method synchronized. This prevents something external to you class from grabbing the lock and stalling things.
Make sure that you use the synchronized keyword everywhere, and make sure you always synchronize on the same object. If you forget to do either of those things, two processes can access the fields at the same time.
Beware of deadlocks. In a perfect world you'd write unit tests to ensure that locking is working the way you think it is.
Use a synchronized block or method to wrap access to the two counters, remember to use the same object to lock on.
What is a good way to implement thread-safe bidirectional associations? Is there maybe a good library or code generator?
Here is a non thread-safe example:
class Foo {
private Foo other;
public Foo getOther() {
return other;
}
public void setOther(Foo other) {
this.setOtherSecretly(other);
other.setotherSecretly(this);
}
void setOtherSecretly(Foo other) {
if (this.other != null) this.other.other = null;
this.other = other;
}
}
My requirements for thread-safety are:
No deadlocks
Eventual consistency (When all threads stop modifying the objects, a consistent state is eventually reached. I.e., it is acceptable that assert foo.getOther().getOther() == foo fails when another thread is performing setOther concurrently.
Sequential behaviour. If a thread performs setOther and no other other thread overrides the value, getOther immediately returns the new value for that thread.
No traveling back in time. Once a thread observed a new value with getOther, it will never again receive the old value (unless it is set again).
Also nice to have:
Low contention, especially no global lock. The solution should scale well.
As little synchronization overhead as possible. It should have reasonable performance for a single thread.
Low memory overhead. When an object has 5 associations, I don't want 3 additional fields per association. Local variables in setters are ok.
My application will have 16 threads working on about 5.000 objects of several classes.
I couldn't come up with a solution yet (no, this is not homework), so any input (ideas, articles, code) is welcome.
Google Guava does this for you: BiMap.
For example:
BiMap<Integer, String> bimap = Synchronized.biMap(HashBiMap.create(), someMutexObject);
bimap.put(1, "one");
bimap.put(2, "two");
bimap.get(1); // returns "one"
bimap.inverse().get("one") // returns 1
someMutexObject can be any object you would want to synchronize on.
You can associate each object to their own lock and then set the other while acquiring both locks. For instance. To avoid deadlock you can use lock ordering
class Foo extends ReentrantLock {
private static final AtomicInteger order = new AtomicInteger(0);
final int id = order.incrementAndGet();
private Foo other;
public Foo getOther() {
return other;
}
public void setOther(Foo other) {
if (id > other.id) {
other.lock();
try {
this.lock();
try {
// assign here
} finally {
this.unlock();
}
} finally {
other.unlock();
}
} else if (id < other.id) {
this.lock();
try {
other.lock();
try {
// assign here
} finally {
other.unlock();
}
} finally {
this.unlock();
}
}
}
}
Try this, will allow reading while no writing is done.
ReentrantReadWriteLock
The other alternative is to simply make the other reference(s) volatile. That will meet your requirement and your nice-to-haves.
I can think of an static member to work as a monitor. but maybe this is what you consider 'global' lock.
class Foo {
private static final Object MONITOR = new Object();
private Foo other;
public Foo getOther() {
synchronized(MONITOR){
return other;
}
}
public void setOther(Foo other) {
synchronized(MONITOR){
this.setOtherSecretly(other);
other.setotherSecretly(this);
}
}
void setOtherSecretly(Foo other) {
if (this.other != null) this.other.other = null;
this.other = other;
}
}
This turns out to be a really hard problem! (Nice!) Using a global lock would be too easy, and probably too slow. I think I have a lock-free version--which I'll get into below--but I wouldn't put too much faith in it being perfect. It's hard to reason about all the possible interleavings.
As it turns out, this is a perfect use case for transactional memory! Just mark the whole block as atomic and modify whatever you want! You might look at Deuce STM, though I don't know how fast it might be. If only the best systems didn't need custom hardware...
Anyway, after thinking through this problem for a while, I think I came up with a version that bypasses locks using Java's AtomicReference. First, the code:
class Foo {
private AtomicReference<Foo> oRef = new AtomicReference<Foo>;
private static final AtomicInteger order = new AtomicInteger(0);
private final int id = order.incrementAndGet();
private static bool break(Foo x, Foo y) {
if (x.id > y.id)
return break(y, x);
return x.oRef.compareAndSet(y, null) &&
y.oRef.compareAndSet(x, null);
}
public void setOther(Foo f) {
if (f != null && f.id > id) {
f.setOther(this);
return;
}
do {
Foo other = oRef.get();
if (other == f)
break;
if (other != null && !break(this, other))
continue;
if (f == null)
break;
Foo fother = f.oRef.get();
if (fother != null && !break(f, fother))
continue;
if (!f.oRef.compareAndSet(null, this))
continue;
if (!oRef.compareAndSet(null, f)) {
f.oRef.set(null);
continue;
}
} while (false);
}
}
Key points:
If there are no concurrent accesses to any of the affected Foos (at most 4), the setter makes one pass through the loop modifying the relevant pointers.
In the presence of concurrent setters, some of the setters might fail and retry.
If multiple threads try to break a relationship concurrently, only one thread will succeed executing x.oRef.compareAndSet(y, null).
If f.oRef.compareAndSet(null, f) succeeds, no other thread will be able to break the half-established relationship in break(). Then if oRef.compareAndSet(null, f) succeeds, the operation is complete. If it fails, f.oRef can be reset and everyone retries.