Changes in Java 6 synchronization? - java

I am looking at some code that is causing an issue (Deadlock) in Java 6 and above, but not in Java 1.5.
BMP Bean:
private MyClass m_c;
public String ejbCreate(String id) throws CreateException, MyException
{
try
{
m_c = Singleton.getInstance().getObj(id);
}
catch (MyException e)
{
synchronized (Singleton.getInstance())
{
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
}
else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
Singleton:
private Map objCache = new HashMap();
private static Singleton INSTANCE = new Singleton();
public static Singleton getInstance() {
return INSTANCE;
}
public void addObj(String id, MyClass o)
{
if (this.objCache.containsKey(id)) {
this.objCache.remove(id);
}
this.objCache.put(id, o);
}
public MyClass getObj(String id) throws Exception
{
MyClass o = null;
o = (MyClass)this.objCache.get(id);
if (o == null) {
throw new MyException("Obj " +id+ " not found in cache");
}
return o;
}
public boolean hasObj(String id)
{
return this.objCache.containsKey(id);
}
The empirical evidence so far shows that putting synchronization round the whole try/catch resolves the deadlock when using Java 6.
Clearly there can be one or more threads calling
Singleton.getInstance().getObj(id)
without obtaining the lock whilst another thread has the lock and is executing the code in the synchronized block, but even after considering memory synchronization detailed in JSR-133, it doesn't look like there should be any issues in this scenario.
I am aware that I haven't explained what the issue is apart from saying it is a deadlock and that it is not ideal to paint only a prat of the picture but to paint the whole picture would take a very big canvas.
I have looked at the notes for Java 6 release and the only area that sounds relevant is around uncontended synchronization, but I do not know if that is significant in this case.
Thank you for any help.

I suspect you are not getting a deadlock (holding two locks in two different threads obtained in a different order), but rather going into an infinite loop. This can happen with HashMap if you are accessing it in a manner which is not thread safe. What happens in the linked list used to handle collisions appears to go back on itself and the reader runs forever. This has always been an issue, though some subtle difference in Java 6 could show up this problem when a different version might not.
I suggest you fix this class so it uses a thread safe collection and not retry on Exception because there is not guarantee this will happen.
There is a lot you could do to improve this class but what you really need is ConcurrentMap.computeIfAbsent added in Java 8.
Note: there is no reason to
check a key exists before attempting to remove it.
remove a key just before attempting to put it.
throw an Exception instead of returning null.
returning null when you can pass it a factory. (as per computeIfAbsent)
use a factory when the type is known in advance.
I suggest you
use a ConcurrentMap for thread safe concurrent access.
use an enum for a Singleton.
Both of these were added in Java 5.0.
public enum MyClassCache {
INSTANCE;
private final Map<String, MyClass> cache = new ConcurrentHashMap<>();
public boolean hasId(String id) {
return cache.containsKey(id);
}
public MyClass get(String id) throws IllegalStateException {
MyClass ret = cache.get(id);
if (ret == null) throw new IllegalStateException(id);
return ret;
}
public MyClass getOrCreate(String id) throws IllegalStateException {
MyClass ret = cache.get(id);
if (ret == null) {
synchronized (cache) {
ret = cache.get(id);
if (ret == null) {
cache.put(id, ret = new MyClass(id));
}
}
}
return ret;
}
}
In Java 8 you can use computeIfAbsent
public MyClass getOrCreate(String id) {
return cache.computeIfAbsent(id, MyClass::new);
}

Am I right that the core of this question is the difference between:
public void ejbCreate1(String id) throws Exception {
try {
m_c = Singleton.getInstance().getObj(id);
} catch (Exception e) {
synchronized (Singleton.getInstance()) {
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
} else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
and
public void ejbCreate2(String id) throws Exception {
synchronized (Singleton.getInstance()) {
try {
m_c = Singleton.getInstance().getObj(id);
} catch (Exception e) {
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
} else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
in Java-6 that can cause the first to hang and the second to work fine.
Clearly the primary difference is that getObj might be called by two different threads at the same time, and may even be called while another threads is creating the new object.
From Is it safe to get values from a java.util.HashMap from multiple threads (no modification)? it is likely that you are not in that situation. Conclusion is that one thread is readng from the Map (perhaps o = (MyClass) this.objCache.get(id);) while another is writing to the map by calling addObj. This is clearly a recipe for the read to crash and burn.
See Is a HashMap thread-safe for different keys? for details about the potential sinkholes.

Related

Does synchronisation with ConcurrentHashMap's .compute() guarantee visibility?

Within ConcurrentHashMap.compute() I increment and decrement some long value located in shared memory. Read, increment/decrement only gets performed within compute method on the same key.
So the access to long value is synchronised by locking on ConcurrentHashMap segment, thus increment/decrement is atomic. My question is: Does this synchronisation on a map guarantee visibility for long value? Can I rely on Map's internal synchronisation or should I make my long value volatile?
I know that when you explicitly synchronise on a lock, visibility is guaranteed. But I do not have perfect understanding of ConcurrentHashMap internals. Or maybe I can trust it today but tomorrow ConcurrentHashMap's internals may somehow change: exclusive access will be preserved, but visibility will disappear... and it is an argument to make my long value volatile.
Below I will post a simplified example. According to the test there is no race condition today. But can I trust this code long-term without volatile for long value?
class LongHolder {
private final ConcurrentMap<Object, Object> syncMap = new ConcurrentHashMap<>();
private long value = 0;
public void increment() {
syncMap.compute("1", (k, v) -> {
if (++value == 2000000) {
System.out.println("Expected final state. If this gets printed, this simple test did not detect visibility problem");
}
return null;
});
}
}
class IncrementRunnable implements Runnable {
private final LongHolder longHolder;
IncrementRunnable(LongHolder longHolder) {
this.longHolder = longHolder;
}
#Override
public void run() {
for (int i = 0; i < 1000000; i++) {
longHolder.increment();
}
}
}
public class ConcurrentMapExample {
public static void main(String[] args) throws InterruptedException {
LongHolder longholder = new LongHolder();
Thread t1 = new Thread(new IncrementRunnable(longholder));
Thread t2 = new Thread(new IncrementRunnable(longholder));
t1.start();
t2.start();
}
}
UPD: adding another example which is closer to the code I am working on. I would like to remove map entries when no one else is using the object. Please note that reading and writing of the long value happens only inside of remapping function of ConcurrentHashMap.compute:
public class ObjectProvider {
private final ConcurrentMap<Long, CountingObject> map = new ConcurrentHashMap<>();
public CountingObject takeObjectForId(Long id) {
return map.compute(id, (k, v) -> {
CountingObject returnLock;
returnLock = v == null ? new CountingObject() : v;
returnLock.incrementUsages();
return returnLock;
});
}
public void releaseObjectForId(Long id, CountingObject o) {
map.compute(id, (k, v) -> o.decrementUsages() == 0 ? null : o);
}
}
class CountingObject {
private int usages;
public void incrementUsages() {
--usages;
}
public int decrementUsages() {
return --usages;
}
}
UPD2: I admit that I failed to provide the simplest code examples previously, posting a real code now:
public class LockerUtility<T> {
private final ConcurrentMap<T, CountingLock> locks = new ConcurrentHashMap<>();
public void executeLocked(T entityId, Runnable synchronizedCode) {
CountingLock lock = synchronizedTakeEntityLock(entityId);
try {
lock.lock();
try {
synchronizedCode.run();
} finally {
lock.unlock();
}
} finally {
synchronizedReturnEntityLock(entityId, lock);
}
}
private CountingLock synchronizedTakeEntityLock(T id) {
return locks.compute(id, (k, l) -> {
CountingLock returnLock;
returnLock = l == null ? new CountingLock() : l;
returnLock.takeForUsage();
return returnLock;
});
}
private void synchronizedReturnEntityLock(T lockId, CountingLock lock) {
locks.compute(lockId, (i, v) -> lock.returnBack() == 0 ? null : lock);
}
private static class CountingLock extends ReentrantLock {
private volatile long usages = 0;
public void takeForUsage() {
usages++;
}
public long returnBack() {
return --usages;
}
}
}
No, this approach will not work, not even with volatile. You would have to use AtomicLong, LongAdder, or the like, to make this properly thread-safe. ConcurrentHashMap doesn't even work with segmented locks these days.
Also, your test does not prove anything. Concurrency issues by definition don't happen every time. Not even every millionth time.
You must use a proper concurrent Long accumulator like AtomicLong or LongAdder.
Do not get fooled by the line in the documentation of compute:
The entire method invocation is performed atomically
This does work for side-effects, like you have in that value++; it only works for the internal data of ConcurrentHashMap.
The first thing that you miss is that locking in CHM, the implementation has changed a lot (as the other answer has noted). But even if it did not, your understanding of the:
I know that when you explicitly synchronize on a lock, visibility is guaranteed
is flawed. JLS says that this is guaranteed when both the reader and the writer use the same lock; which in your case obviously does not happen; as such no guarantees are in place. In general happens-before guarantees (that you would require here) only work for pairs, for both reader and writer.

Java Set gets full

I am making a particle emitter.
Every "Rendered" object is stored in a HashSet, and when there's lots of particles on the screen, the console spits out concurrent modification exceptions. I usually have a short lifetime on these particles so they get deleted after several seconds, but I am sure this could potentially be a problem in the future. How can I fix this?
EDIT: Code:
public class UpdatedManager {
private static Set<Updated> updates = new HashSet<>();
private UpdatedManager() {}
public static Set<Updated> getUpdates() {
return new HashSet<Updated>(updates);
}
public static boolean registerUpdated(Updated u) {
return updates.add(u);
}
public static boolean unregisterUpdated(Updated u) {
return updates.remove(u);
}
public static void update() {
for (Updated up : new HashSet<Updated>(updates))
up.update();
}
public static Set<GameObject> getGameObjects() {
Set<GameObject> objs = new HashSet<>();
for (Updated up : new HashSet<Updated>(updates)) {
if (up instanceof GameObject)
objs.add((GameObject) up);
}
return objs;
}
public static Set<GameObject> getGameObjectsByName(String name) {
Set<GameObject> objs = new HashSet<>();
for (GameObject go : new HashSet<GameObject>(getGameObjects())) {
if (go.getName() != null && go.getName().equals(name))
objs.add(go);
}
return objs;
}
public static Set<Particle> getParticles() {
Set<Particle> parts = new HashSet<>();
for (Updated up : new HashSet<Updated>(updates)) {
if (up instanceof Particle)
parts.add((Particle) up);
}
return parts;
}
}
A ConcurrentModificationException means you modified the set while iterating over it. It does not mean the set is full.
For example, the following code will throw a ConcurrentModificationException:
Set<String> set = new HashSet<>();
set.add("Hello");
for(String s : set)
set.add(s+" world");
Note that you are not guaranteed to get a ConcurrentModificationException, so you should avoid catching it. You should instead fix your code so that it doesn't cause the problem.
What makes you think that the set is full?
Concurrent modification exceptions mean that the set is being accessed by different threads in an unsafe manner.
Try a synchronised set using the Collections utilities
HashSet hashSet = new HashSet();
Set set = Collections.synchronizedSet(hashSet);
or use the synchronized keyword for the method accessing the set.

Spurious ConcurrentModificationException

I'm having some issues with a piece of java code which keeps triggering a ConcurrentModificationException. I can't really figure out what is going on, this is a fairly simple static class, not sure why it would be throwing this exception as everything is synchronized. This piece of code has been heavily used for several years, so it's odd that it would start having issues at this point:
java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:953)
at java.util.LinkedList$ListItr.next(LinkedList.java:886)
at DataSubscriptionManager.sendMessages(DataSubscriptionManager.java:18)
private static HashMap<DataClass,LinkedList<DataSubscriber>> subscriberMap = new HashMap();
public static void sendMessages(LinkedList messages, DataClass dataClass) {
synchronized (subscriberMap) {
LinkedList<DataSubscriber> subscribers = subscriberMap.get(dataClass);
if (subscribers != null) {
for (DataSubscriber sub: subscribers) { *** EXCEPTION HAPPENS HERE***
if (sub != null) {
sub.sendMessages(messages);
}
}
}
}
}
public static void addDataSubscriber(DataSubscriber sub, DataClass dataClass) {
synchronized (subscriberMap) {
LinkedList<DataSubscriber> subscribers = subscriberMap.get(dataClass);
if (subscribers == null) {
subscribers = new LinkedList();
subscriberMap.put(dataClass,subscribers);
}
while (subscribers.remove(sub)) {}
subscribers.add(sub);
}
}
public static void removeDataSubscriber(DataSubscriber sub, DataClass dataClass) {
synchronized (subscriberMap) {
LinkedList<DataSubscriber> subscribers = subscriberMap.get(dataClass);
subscribers.remove(sub);
}
}
What's happening is that your collection is being modified while you are iterating over it.
It's could be another thread, or it's possible one of your subscribers is either unsubscribing, or subscribing to a different dataClass in response to the message it receives.
You can try using Collections.synchronizedList(subscribers) which may help avoiding this problem.

Synchronization work with conditionals? How can I make this code performant and thread safe?

Given the following code:
public class SomeClass {
private boolean shouldBlock = false;
private Object resource;
public void handleDrawRequest(Canvas canvas) {
if (!shouldBlock && resource == null)
{
shouldBlock = true;
loadTheResource(); //which takes awhile
shouldBlock = false;
}
else if (shouldBlock && resrouce == null)
{
return; //another thread is taking care of the loading of the resource
//and its not ready yet, so just ignore this request
}
drawResourceOn(canvas);
}
}
How can I make this code thread safe? What I'm trying to accomplish is for one and only one thread to load the resource while any other thread attempting access this code at the same time to be discarded (e.g. follow the 'else if' logic) until the resource is loaded. There could be many threads trying to access this code at the same time and I don't want to synchronize the entire method and have a whole stack of threads pile up.
With double checked non-blocking locking:
public class SomeClass {
private Lock lock = new Lock();
private volatile Object resource;
public void handleDrawRequest(Canvas canvas) {
if( resource==null ) {
if( lock.tryLock() ) {
try {
if( resource==null )
resource = loadResource();
}
finally {
lock.unlock();
}
}
else {
return;
}
}
drawResourceOn(canvas);
}
}
If you don't make resource volatile, threads are free to cache it and might never read the updated value. In particular, the second null check will always return true, even if the resource has been loaded after the first one.
You're looking for an AtomicBoolean
public class SomeClass {
// AtomicBolean defaults to the value false.
private AtomicBoolean loadingResource = new AtomicBoolean();
private volatile Object resource;
public void handleDrawRequest(Canvas canvas) {
if (resource == null) {
if (loadingResource.compareAndSet(false, true)) {
loadTheResource(); //which takes awhile
} else {
//another thread is taking care of the loading of the resource
//and its not ready yet, so just ignore this request
return;
}
} else {
drawResourceOn(canvas);
}
}
}

DelayQueue with capacity

I'm using a DelayQueue. I need to use this so as to only take from the queue when a delay has passed. I also want to enforce a capacity, much like a BlockingQueue. I can't seem to find a Collections implementation of this. Does one exist? If not, what's the best way of implementing it? A basic approach would be to do something like this:
public void addSomethingToQueue(Object somethingToAdd){
int capacity = 4;
while(queue.size() >= capacity){
try{
wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
queue.add(somethingToAdd);
}
This would mean calling notify / notifyAll each time something was removed. It's quite a small class so that's doable. It doesn't sound great though. And I'm not sure if the wait / notify may cause further problems?
Would it be better to sub-class DelayQueue and mess around with its methods? It feels a bit dodgy...
Why not compose a BlockingQueue and a DelayQueue? For e.g.:
class MyDelayBlockingQueue<T> implements Queue {
private final DelayQueue<T> delayQ = ...
private final BlockingQueue<T> blockingQ = ...
public synchronized void offer(T obj) {
blockingQ.offer(obj); // this will block if the Q is full
delayQ.offer(obj);
}
public synchronized T poll() {
T obj = delayQ.poll(); // This will handle the delay
if (obj != null) {
blockingQ.poll();
}
return obj;
}
// ...
}
EDIT
The code above will deadlock. If the Q is full, offer will block in a synchronized block, and all future calls to poll will block to acquire the intrinsic lock of the Q - causing a deadlock. Try something like instead:
public class DelayBlockingQueue<E extends Delayed>
{
private final DelayQueue<E> delayQ = new DelayQueue<E>();
private final Semaphore available;
public DelayBlockingQueue(int capacity)
{
available = new Semaphore(capacity, true);
}
public void offer(E e) throws InterruptedException
{
available.acquire();
delayQ.offer(e);
}
public E poll()
{
E e = delayQ.poll();
if (e != null)
{
available.release();
}
return e;
}
}
You may using LRU:
http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
Example implementation from Apache Commons:
http://commons.apache.org/collections/api/org/apache/commons/collections/LRUMap.html
So you don't write this again ;-)

Categories

Resources