Finally reading through the excellent Concurrency In Practice book and I am came across listing 14.2 for BaseBoundedBuffer. As is, the put and take methods will allow for count to exceed the buffer capacity or go below 0. I get that the class is abstract but it seems strange this is the default behaviour. Is there some good reason why there would not be some logic to not allow count to go beyond capacity or below 0? Maybe something like,
if(count != buf.length)
++count;
#ThreadSafe
public abstract class BaseBoundedBuffer<V> {
#GuardedBy("this") private final V[] buf;
#GuardedBy("this") private final int tail;
#GuardedBy("this") private final int head;
#GuardedBy("this") private final int count;
protected BaseBoundedBuffer (int capacity) {
this.buf = (V[]) new Object[capacity];
}
protected synchronized final void doPut(V v) {
buf[tail] = v;
if (++tail == buf.length)
tail = 0;
++count;
}
protected synchronized final V doTake() {
V v = buf[head];
buf[head] = null;
if (++head == buf.length)
head = 0;
--count;
return v;
}
public synchronized final boolean isFull() {
return count == buf.length;
}
public synchronized final boolean isEmpty() {
return count == 0;
}
}
It seems given the example child class in the book that it was intended for the child class to have the responsibility of checking isFull before putting and isEmpty before taking. With such an implementation, checking again is a waste of time.
#ThreadSafe
public class GrumpyBoundedBuffer<V> extends BaseBoundedBuffer<V> {
public GrumpyBoundedBuffer(int size) { super(size); }
public synchronized void put(V v) throws BufferFullException {
if (isFull())
throw new BufferFullException();
doPut(v);
}
public synchronized V take() throws BufferEmptyException {
if (isEmpty())
throw new BufferEmptyException();
return doTake();
}
}
In the real world, an appropriate JavaDoc explaining how these methods are intended to be used would be crucial to avoiding the two potential bugs you have identified.
It should go without saying that just because something is in a book doesn't mean it is correct, optimal, or even good. You were right to be skeptical about the implementation.
We should never let count run out of bounds, but this example supposes that checking this condition is propagated to the caller. We can't just throw an exception, because in a multithreaded program such behavior may be expected and handled in a non-exceptional way (e.g. just waiting for the condition to fulfill). We can't just say if(count != buf.length) ++count; either, because this would be a part of handling logic and could clash with the logic implemented in the caller or subclass.
This example is a part of a bigger picture - the chapter 14.1.1. Example: propagating precondition failure to callers describes an approach where the exceptional case is handled by the subclass. The chapter describes two "painful" ways to implement such functionality (throwing an exception or sleeping the thread) and then provides a more robust approach - using condition queues (see chapter 14.1.3).
I'd like to stress that the code example you've mentioned is not an implementation to copy-and-paste, it's just means of getting to the point.
Related
I want to do operations like
class A {
}
ConcurrentHashMap<A, Integer> map = new ConcurrentHashMap<>();
public void fun() {
Integer count = map.get(Object);
if (count != null) {
map.put(Object, count+1);
}
}
public void add() {
// increase Object count by 1
}
public void remove() {
// deduct Object count by 1
}
How can I make fun() thread safe ?
I know a way to do this is to add synchronized block
public void fun() {
synchronized("") {
Integer count = map.get(Object);
if (count != null) {
map.put(Object, count+1);
}
}
}
But are there any other ways to do it ?
Or are there any libraries to do it ?
like thread safe entry processor ?
I also want to implement something like
public void remove() {
int count = map.get(Object);
count -= 5;
if (count <= 0) {
map.remove(Object);
} else {
map.put(Object, count + 2);
}
}
Any ways to do this ?
Thank you
Use AtomicInteger and ConcurrentHashMap.putIfAbsent()
Also look at the
ConcurrentHashMap.remove(key, value) -- removes the key only if it is mapped to the given value.
I am not sure, if it is possible to implement the exact logic (which is not very well defined in the question above), but those methods could be very useful in doing something similar.
More hints (that could be useful or may be not too much):
You (probably!) can use methods: computeIfAbsent, computeIfPresent (or replace), and remove(key, value).
ConcurrentHashMap could be defined on values are Integers.
It will be very dirty solution, and I do not recommend you to use it, but as something to think about, it could be very challenging.
Let me know if you need more hints.
I was recently asked a question that stumped me.
public void swapEngine(Car a, Car b) {
Engine temp = a.engine;
a.engine = b.engine;
b.engine = temp;
}
This is not a thread-safe method. If Thread 1 calls swapEngine(car1, car2) and then Thread 2 calls swapEngine(car1, car3), it is possible for car2 to end up with the engine of car3. The most obvious way to fix this problem is to synchronize the method.
Synchronizing the method introduces a potential inefficiency. What if Thread 1 calls swapEngine(car1, car2) and Thread 2 calls swapEngine(car3, car4)? In no way can these two threads interfere with each other. In this case the ideal situation would be for the two threads to swap the engines in parallel. Synchronizing the method precludes this from happening.
Is there another technique to swap these engines in a thread-safe manner while still taking advantage of parallelism?
Edit: Made method public.
As the comments say, you can lock the cars themselves. This, however could cause a deadlock if cars are not always locked in the same order.
So, if cars have a unique identifier, you can simply sort the cars, and then swap:
void swapEngine(Car a, Car b) {
Comparator<Car> byId = Comparator.comparing(Car::id);
Car[] cars = new Car[] {a, b};
Arrays.sort(cars, byId);
doSwap(cars[0]), cars[1];
}
private void doSwap(Car a, Car b) {
synchronized(a) {
synchronized(b) {
Engine temp = a.engine;
a.engine = b.engine;
b.engine = temp;
}
}
}
If the cars don't have any unique ID allowing to compare them, you can sort them by their identity hashCode (obtained using System.identityHashCode(car)). This hashCode, unless you have a huge memory, an enormous amount of cars, and bad luck, is unique. If you really fear such a situation, then Guava has an arbitrary ordering that you can use.
If you store Car.engine in AtomicReference, you could swap them using the CAS operations:
public <T> void atomicSwap(AtomicReference<T> a, AtomicReference<T> b) {
for(;;) {
T aa = a.getAndSet(null);
if (aa != null) {
T bb = b.getAndSet(null);
if (bb != null) {
// this piece will be reached ONLY if BOTH `a` and `b`
// contained non-null (and now contain null)
a.set(bb);
b.set(aa);
return;
} else {
// if `b` contained null, try to restore old value of `a`
// to avoid deadlocking
a.compareAndSet(null, aa);
}
}
}
}
Advantage of this approach is that it doesn't require right object ordering and don't use intrinsic locks. It also doesn't need to lock on full object--other properties can be manipulated in parallel.
Disadvantage is that now null values are illegal: they mean that operation on variable is in progress. You'll need to check for null when getting values and setting them anywhere but in constructor:
public <T> T getValue(AtomicReference<T> a) {
for(;;) {
T v = a.get();
if (v != null)
return v;
}
}
public <T> T setValue(AtomicReference<T> a, T value) {
for(;;) {
T old = a.get();
if (old != null && a.compareAndSet(old, value))
return old;
}
}
I have a key-value map accessed by multiple threads:
private final ConcurrentMap<Key, VersionValue> key_vval_map = new ConcurrentHashMap<Key, VersionValue>();
My custom get() and put() methods follow the typical check-then-act pattern. Therefore, synchronization is necessary to ensure atomicity. To avoid locking the whole ConcurrentHashMap, I define:
private final Object[] locks = new Object[10];
{
for(int i = 0; i < locks.length; i++)
locks[i] = new Object();
}
And the get() method goes (it calls the get() method of ConcurrentHashMap):
public VersionValue get(Key key)
{
final int hash = key.hashCode() & 0x7FFFFFFF;
synchronized (locks[hash % locks.length]) // I am not sure whether this synchronization is necessary.
{
VersionValue vval = this.key_vval_map.get(key);
if (vval == null)
return VersionValue.RESERVED_VERSIONVALUE; // RESERVED_VERSIONVALUE is defined elsewhere
return vval;
}
}
The put() method goes (it calls the get() method above):
public void put(Key key, VersionValue vval)
{
final int hash = key.hashCode() & 0x7FFFFFFF;
synchronized (locks[hash % locks.length]) // allowing concurrent writers
{
VersionValue current_vval = this.get(key); // call the get() method above
if (current_vval.compareTo(vval) < 0) // it is an newer VersionValue
this.key_vval_map.put(key, vval);
}
}
The above code works. But, as you know, working is far from being correct in multi-threaded programming.
My questions are :
Is this synchronization mechanism (especially synchronized (locks[hash % locks.length])) necessary and correct in my code?
In Javadoc on Interface Lock, it says
Lock implementations provide more extensive locking operations than
can be obtained using synchronized methods and statements.
Then is it feasible to replace synchronization by Lock in my code?
Edit: If you are using Java-8, don't hesitate to refer to the answer by #nosid.
ConcurrentMap allows you to use optimistic locking instead of explicit synchronization:
VersionValue current_vval = null;
VersionValue new_vval = null;
do {
current_vval = key_vval_map.get(key);
VersionValue effectiveVval = current_vval == null ? VersionValue.RESERVED_VERSIONVALUE : current_vval;
if (effectiveVval.compareTo(vval) < 0) {
new_vval = vval;
} else {
break;
}
} while (!replace(key, current_vval, new_vval));
...
private boolean replace(Key key, VersionValue current, VersionValue newValue) {
if (current == null) {
return key_vval_map.putIfAbsent(key, newValue) == null;
} else {
return key_vval_map.replace(key, current, newValue);
}
}
It will probably have better performance under low contention.
Regarding your questions:
If you use Guava, take a look at Striped
No, you don't need additional functionality of Lock here
If you are using Java-8, you can use the method ConcurrentHashMap::merge instead of reading and updating the value in two steps.
public VersionValue get(Key key) {
return key_vval_map.getOrDefault(key, VersionValue.RESERVED_VERSIONVALUE);
}
public void put(Key key, VersionValue vval) {
key_vval_map.merge(key, vval,
(lhs, rhs) -> lhs.compareTo(rhs) >= 0 ? lhs : rhs);
}
I have a following code snippet (The code is in Java, but I have tried to reduce as much clutter as possible):
class State {
public synchronized read() {
}
public synchronized write(ResourceManager rm) {
rm.request();
}
public synchronized returnResource() {
}
}
State st1 = new State();
State st2 = new State();
State st3 = new State();
class ResourceManager {
public syncronized request() {
st2 = findIdleState();
return st2.returnResource();
}
}
ResourceManager globalRM = new ResourceManager();
Thread1()
{
st1.write(globalRM);
}
Thread2()
{
st2.write(globalRM);
}
Thread3()
{
st1.read();
}
This code snippet has the possibility of entering a deadlock with the following sequence of calls:
Thread1: st1.write()
Thread1: st1.write() invokes globalRM.request()
Thread2: st2.write()
Thread1: globalRM.request() tries to invoke st2.returnResource(), but gets blocked because Thread2 is holding a lock on st2.
Thread2: st2.write() tries to invoke globalRM.request(), but gets blocked because globalRM's lock is with Thread1
Thread3: st2.read(), gets blocked.
How do I solve such a deadlock? I thought about it for a while to see there is some sort of ordered locks approach I can use to acquire the locks, but I cannot think of such a solution. The problem is that, the resource manager is global, while states are specific to each job (each job has an ID which is sequential which can be used for ordering if there is some way to use order for lock acquisition).
There are some options to avoid this scenario, each has its advantages and drawbacks:
1.) Use a single lock object for all instances. This approach is simple to implement, but limits you to one thread to aquire the lock. This can be reasonable if the synchronized blocks are short and scalability is not a big issue (e.g. desktop application aka non-server). The main selling point of this is the simplicity in implementation.
2.) Use ordered locking - this means whenever you have to aquire two or more locks, ensure that the order in which they are aquired is the same. Thats much easier said then done and can require heavy changes to the code base.
3.) Get rid of the locks completely. With the java.util.concurrent(.atomic) classes you can implement multithreaded data structures without blocking (usually using compareAndSet-flavor methods). This certainly requires changes to the code base and requires some rethinking of the structures. Usually reqiures a rewrite of critical portions of the code base.
4.) Many problems just disappear when you consequently use immutable types and objects. Combines well with the atomic (3.) approach to implement mutable super-structures (often implemented as copy-on-change).
To give any recommendation one would need to know a lot more details about what is protected by your locks.
--- EDIT ---
I needed a lock-free Set implementation, this code sample illustrates it strengths and weaknesses. I did implement iterator() as a snapshot, implementing it to throw ConcurrentModificationException and support remove() would be a little more complicated and I had no need for it. Some of the referenced utility classes I did not post (I think its completely obvious what the missing referenced pieces do).
I hope its at least a little useful as a starting point how to work with AtomicReferences.
/**
* Helper class that implements a set-like data structure
* with atomic add/remove capability.
*
* Iteration occurs always on a current snapshot, thus
* the iterator will not support remove, but also never
* throw ConcurrentModificationException.
*
* Iteration and reading the set is cheap, altering the set
* is expensive.
*/
public final class AtomicArraySet<T> extends AbstractSet<T> {
protected final AtomicReference<Object[]> reference =
new AtomicReference<Object[]>(Primitives.EMPTY_OBJECT_ARRAY);
public AtomicArraySet() {
}
/**
* Checks if the set contains the element.
*/
#Override
public boolean contains(final Object object) {
final Object[] array = reference.get();
for (final Object element : array) {
if (element.equals(object))
return true;
}
return false;
}
/**
* Adds an element to the set. Returns true if the element was added.
*
* If element is NULL or already in the set, no change is made to the
* set and false is returned.
*/
#Override
public boolean add(final T element) {
if (element == null)
return false;
while (true) {
final Object[] expect = reference.get();
final int length = expect.length;
// determine if element is already in set
for (int i=length-1; i>=0; --i) {
if (expect[i].equals(element))
return false;
}
final Object[] update = new Object[length + 1];
System.arraycopy(expect, 0, update, 0, length);
update[length] = element;
if (reference.compareAndSet(expect, update))
return true;
}
}
/**
* Adds all the given elements to the set.
* Semantically this is the same a calling add() repeatedly,
* but the whole operation is made atomic.
*/
#Override
public boolean addAll(final Collection<? extends T> collection) {
if (collection == null || collection.isEmpty())
return false;
while (true) {
boolean modified = false;
final Object[] expect = reference.get();
int length = expect.length;
Object[] temp = new Object[collection.size() + length];
System.arraycopy(expect, 0, temp, 0, length);
ELoop: for (final Object element : collection) {
if (element == null)
continue;
for (int i=0; i<length; ++i) {
if (element.equals(temp[i])) {
modified |= temp[i] != element;
temp[i] = element;
continue ELoop;
}
}
temp[length++] = element;
modified = true;
}
// check if content did not change
if (!modified)
return false;
final Object[] update;
if (temp.length == length) {
update = temp;
} else {
update = new Object[length];
System.arraycopy(temp, 0, update, 0, length);
}
if (reference.compareAndSet(expect, update))
return true;
}
}
/**
* Removes an element from the set. Returns true if the element was removed.
*
* If element is NULL not in the set, no change is made to the set and
* false is returned.
*/
#Override
public boolean remove(final Object element) {
if (element == null)
return false;
while (true) {
final Object[] expect = reference.get();
final int length = expect.length;
int i = length;
while (--i >= 0) {
if (expect[i].equals(element))
break;
}
if (i < 0)
return false;
final Object[] update;
if (length == 1) {
update = Primitives.EMPTY_OBJECT_ARRAY;
} else {
update = new Object[length - 1];
System.arraycopy(expect, 0, update, 0, i);
System.arraycopy(expect, i+1, update, i, length - i - 1);
}
if (reference.compareAndSet(expect, update))
return true;
}
}
/**
* Removes all entries from the set.
*/
#Override
public void clear() {
reference.set(Primitives.EMPTY_OBJECT_ARRAY);
}
/**
* Gets an estimation how many elements are in the set.
* (its an estimation as it only returns the current size
* and that may change at any time).
*/
#Override
public int size() {
return reference.get().length;
}
#Override
public boolean isEmpty() {
return reference.get().length <= 0;
}
#SuppressWarnings("unchecked")
#Override
public Iterator<T> iterator() {
final Object[] array = reference.get();
return (Iterator<T>) ArrayIterator.get(array);
}
#Override
public Object[] toArray() {
final Object[] array = reference.get();
return Primitives.cloneArray(array);
}
#SuppressWarnings("unchecked")
#Override
public <U extends Object> U[] toArray(final U[] array) {
final Object[] content = reference.get();
final int length = content.length;
if (array.length < length) {
// Make a new array of a's runtime type, but my contents:
return (U[]) Arrays.copyOf(content, length, array.getClass());
}
System.arraycopy(content, 0, array, 0, length);
if (array.length > length)
array[length] = null;
return array;
}
}
The answer to any deadlock is to acquire the same locks in the same order. You'll just have to figure out a way to do that.
Why Methode LinkedList.contains() runs quickly than such implementation:
for (String s : list)
if (s.equals(element))
return true;
return false;
I don't see great difference between this to implementations(i consider that search objects aren't nulls), same iterator and equals operation
Let's have a look at the source code (OpenJDK version) of java.util.LinkedList
public boolean contains(Object o) {
return indexOf(o) != -1;
}
public int indexOf(Object o) {
int index = 0;
if (o==null) {
/* snipped */
} else {
for (Entry e = header.next; e != header; e = e.next) {
if (o.equals(e.element))
return index;
index++;
}
}
return -1;
}
As you can see, this is a linear search, just like the for-each solution, so it's NOT asymptotically faster. It'd be interesting to see how your numbers grow with longer lists, but it's likely to be a constant factor slower.
The reason for that would be that this indexOf works on the internal structure, using direct field access to iterate, as opposed to the for-each which uses an Iterator<E>, whose methods must also additionally check for things like ConcurrentModificationException etc.
Going back to the source, you will find that the E next() method returned by the Iterator<E> of a LinkedList is the following:
private class ListItr implements ListIterator<E> {
//...
public E next() {
checkForComodification();
if (nextIndex == size)
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.element;
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
This is considerably "busier" than the e = e.next; in LinkedList.contains! The iterator() of a LinkedList is actually a ListIterator, which has richer features. They aren't needed in your for-each loop, but unfortunately you have to pay for them anyway. Not to mention all those defensive checks for ConcurrentModificationException must be performed, even if there isn't going to be any modification to the list while you're iterating it.
Conclusion
So yes, iterating a LinkedList as a client using a for-each (or more straightforwardly, using its iterator()/listIterator()) is more expensive than what the LinkedList itself can do internally. This is to be expected, which is why contains is provided in the first place.
Working internally gives LinkedList tremendous advantage because:
It can cut corners in defensive checks since it knows that it's not violating any invariants
It can take shortcuts and work with its internal representations
So what can you learn from this? Familiarize yourself with the API! See what functionalities are already provided; they're likely to be faster than if you've had to duplicate them as a client.
I decided to test this and came out with some interesting result
import java.util.LinkedList;
public class Contains {
private LinkedList<String> items = new LinkedList<String>();
public Contains(){
this.addToList();
}
private void addToList(){
for(int i=0; i<2000; i++){
this.items.add("ItemNumber" + i);
}
}
public boolean forEachLoop(String searchFor){
for(String item : items){
if(item.equals(searchFor))
return true;
}
return false;
}
public boolean containsMethod(String searchFor){
if(items.contains(searchFor))
return true;
return false;
}
}
and a JUnit testcase:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class ContainsTest {
#Test
public void testForEachLoop(){
Contains c = new Contains();
boolean result = c.forEachLoop("ItemNumber1758");
assertEquals("Bug!!", true, result);
}
#Test
public void testContainsMethod(){
Contains c = new Contains();
boolean result = c.containsMethod("ItemNumber1758");
assertEquals("Bug!!", true, result);
}
}
This funny thing is when I run the JUnit test the results are :
- testForEachLoop() - 0.014s
- testContainsMethod() - 0.025s
Is this true or I am doing something wrong ?