Java Concurrency in put/get in collections - java

I connect to an external service with an interactive session + a private feed (InputStream) that run on separate threads. On the interactive session, I send outgoing messages and receive synchronous responses with an object containing different fields, one being an ID and a 'status' confirming success or failure. Simultaneously I receive messages on the private feed for this ID with further 'status' updates. I currently store information about the status per ID in a ConcurrentHashMap. It is imperative that I keep a correct sequence of events on these objects but I am currently getting race conditions where I sometimes process and update the objects on the private feed before I receive and process the synchronous response on the interactive session, hence leaving me with an obsolete and incorrect status for the ID.
Ideally, I would have liked to have some type of collection with a PutIfKeyExistOrWait (w timeout) method, that would only update the value if the key exists or else wait, that I could use when processing objects on the private feed.
Does anyone know if there is a suitable collection available or can suggest an alternative solution to my problem? Thanks.

You can try to encapsulate logic for handling this situation into values of your map, something like this:
If feed thread is the first to add a value for particular id, that value is considered incomplete and thread waits until it's completed
If interactive session thread isn't the first to add a value, it marks that incomplete value as complete
Incomplete values are treated as absent when getting them from the map
This solution is based on atomicity of putIfAbsent().
public class StatusMap {
private Map<Long, StatusHolder> map = new ConcurrentHashMap<Long, StatusHolder>();
public Status getStatus(long id) {
StatusHolder holder = map.get(id);
if (holder == null || holder.isIncomplete()) {
return null;
} else {
return holder.getStatus();
}
}
public void newStatusFromInteractiveSession(long id, Status status) {
StatusHolder holder = StatusHolder.newComplete(status);
if ((holder = map.putIfAbsent(id, holder)) != null) {
holder.makeComplete(status); // Holder already exists, complete it
}
}
public void newStatusFromFeed(long id, Status status) {
StatusHolder incomplete = StatusHolder.newIncomplete();
StatusHolder holder = null;
if ((holder = map.putIfAbsent(id, incomplete)) == null) {
holder = incomplete; // New holder added, wait for its completion
holder.waitForCompletion();
}
holder.updateStatus(status);
}
}
public class StatusHolder {
private volatile Status status;
private volatile boolean incomplete;
private Object lock = new Object();
private StatusHolder(Status status, boolean incomplete) { ... }
public static StatusHolder newComplete(Status status) {
return new StatusHolder(status, false);
}
public static StatusHolder newIncomplete() {
return new StatusHolder(null, true);
}
public boolean isIncomplete() { return incomplete; }
public void makeComplete(Status status) {
synchronized (lock) {
this.status = status;
incomplete = false;
lock.notifyAll();
}
}
public void waitForCompletion() {
synchronized (lock) {
while (incomplete) lock.wait();
}
}
...
}

You already have some ConcurrentHashMap iDAndStatus that stores the ID and latest status. However, I would only let the thread that deals with the service create a new entry in that map.
When a message arrives from the feed, if the ID already exists in iDAndStatus, it just modifies the status. If the key does not exist, just store temporarily the ID/status updates in some other data structure, pendingFeedUpdates.
Everytime a new entry is created in iDAndStatus, check pendingFeedUpdates to see if some update(s) for the new ID are present.
I'm not sure what synchronized data structure to use for pendingFeedUpdates: you need to retrieve by ID, but you might have many messages for each ID, and you want to keep the order of the messages. Maybe a synchronized HashMap that associates each ID with some type of synchronized ordered Queue?

I would suggest you look at the Collections.getSynchronized collection:http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#synchronizedList%28java.util.List%29
This could maybe solve you problem the other option depending how the calls are made have the method be a synchronized method that allows for thread safe execution and would ensure atomicity of transaction. See http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
The third option is to enforce a concurrency management control within the application following an optimistic or pessimistic approach depending on what you are trying to achieve. This is the most complex of the 3 but will give you the greater control if coupled with the previous options.
This is really dependent on your specific implementation.

Related

Java possible race condition of Collection in -- spring framework

I am using the spring framework under tomcat to write service that can handle multiple concurrent requests. There is a static variable declared in my service class to be shared across all the threads and protected by a read-write lock. This static collection is read and written to periodically. Each time I update I acquire the write lock and when I read it I acquire the read lock.
The data stored in the collection is entries from a database table. So it is a collection of type List. Basically I have a table that gets updated rarely and so I am caching it in the process memory.
Now there are times when I need to log this data so can I log the return object without acquiring the lock in the method. Or will that cause a race condition? The logging is for the purpose of debugging.
Also, the returned value of the collection is only read only and is not modified by any method. No one outside of the service object uses this Collection.
I feel this should work because when a new collection is allocated the old collection will only go away if all references to it have gone away. And while updating no new references to old or new object are allowed till the write lock is unlocked.
The code looks as follows:
class ObjService {
private static Collection<OtherObj> _staticCollection;
private static ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock(true);
private Collection<OtherObj> getCollection () {
Collection<OtherObj> retVal = null;
rwlock.readLock().lock();
if (_staticCollection != null) {
retVal = _staticCollection;
rwlock.readLock().unlock();
log (retVal);
}
else {
rwlock.readLock().unlock();
ReloadCollectionFromDB ();
rwlock.readLock().lock();
retVal = _staticCollection;
rwlock.readLock().unlock();
}
}
private ReloadCollectionFromDB () {
Collection<OtherObj> otherObjCol = null;
try {
otherObjCol = objRepo.findAll ();
}
catch (Exception ex) {
// log exception
return;
}
rwlock.writeLock().lock();
_staticCollection = otherObjCol;
rwlock.writeLock().unlock();
}
// periodically get data from DB
#Scheduled(initialDelayString = "120000", fixedDelayString = "540000")
void readLoadCache () {
ReloadCollectionFromDB ();
}
}
If there are better ways of doing this, I would appreciate some guidance.
Many thanks,
~Ash

Synchronized block accessed by two threads

I have a synchronized method that is being called from a controller method.
When two request access this only one should go through and other should be blocked until first is finished.
But when the incoming requests are fast, this is actually returning same accountId to two different requests, which is not intended.
Please help me understand how do I synchronize this getNextAccount() call so that it only return one account to one request.
Method in AccService.java
private final Object lockObject = new Object();
#Transactional(propagation = Propagation.REQUIRES_NEW)
public Long getNextAccount(String hostport) {
synchronized (lockObject) {
Long acc = null;
try {
AccountFetch dtls = getAccount();
if (dtls != null) {
acc = dtls.getAccId();
//Set IN_PROGRESS
dtls.setStatus("Progress");
dtls.saveAndFlush(dtls);
return acc;
} else {
log.info("No More Accounts to Process");
}
} catch (Exception e) {
e.getStackTrace();
}
return acc;
}
}
#Autowired
private AccService accSevice;
#GET
#Path("/accprocess")
#Produces(MediaType.APPLICATION_JSON)
public AccountFetch getAccId(#QueryParam("currentHost") final String currentHost,
#QueryParam("currentPort") final String currentPort) {
AccountFetch dtls = new AccountFetch();
try {
Long batchId = accSevice. getNextAccount(currentHost+"#"+currentPort);
if (accId != null) {
dtls.setAccId(String.valueOf(accId));
} else {
dtls.setAccId(BLANK_STRING);
}
} catch (Exception e) {
log.error("Exception while getting accId : " + e.getMessage());
}
return dtls;
}
public AccountFetch getAccount(){...}
A synchronized block will only give you mutual exclusion if the threads are on the same host, and if they are locking using the same lock object.
Based on what you originally wrote in your question, it seems that one or both of these preconditions is not satisfied. If (as it now transpires) there is only one host processing these requests, then we must consider the other possibility; i.e. that there multiple instances of the AccService object processing requests.
It is also possible that synchronization is working, and the problem is somewhere else. For example, getAccount() could be returning the same account on successive calls.
Basically, there are too many parts of your code-base that we can't see. This means that we can only theorize as to what is causing the problem. If every thing was done correctly; i.e.
there is only one host,
all threads are sharing the same lock object,
getAccount() is implemented correctly, and
nothing else updates the account state used by getAccount without proper synchronization,
then the code you have shown us would work.
If you need more help, an MCVE is probably required.

Lock or wait cache load

We need to lock a method responsible for loading database date into a HashMap based cache.
A possible situation is that a second thread tries to access the method while the first method is still loading cache.
We consider the second thread's effort in this case to be superfluous. We would therefore like to have that second thread wait until the first thread is finished, and then return (without loading the cache again).
What I have works, but it seems quite inelegant. Are there better solutions?
private static final ReentrantLock cacheLock = new ReentrantLock();
private void loadCachemap() {
if (cacheLock.tryLock()) {
try {
this.cachemap = retrieveParamCacheMap();
} finally {
cacheLock.unlock();
}
} else {
try {
cacheLock.lock(); // wait until thread doing the load is finished
} finally {
try {
cacheLock.unlock();
} catch (IllegalMonitorStateException e) {
logger.error("loadCachemap() finally {}",e);
}
}
}
}
I prefer a more resilient approach using read locks AND write locks. Something like:
private static final ReadWriteLock cacheLock = new ReentrantReadWriteLock();
private static final Lock cacheReadLock = cacheLock.readLock();
private static final Lock cacheWriteLock = cacheLock.writeLock();
private void loadCache() throws Exception {
// Expiry.
while (storeCache.expired(CachePill)) {
/**
* Allow only one in - all others will wait for 5 seconds before checking again.
*
* Eventually the one that got in will finish loading, refresh the Cache pill and let all the waiting ones out.
*
* Also waits until all read locks have been released - not sure if that might cause problems under busy conditions.
*/
if (cacheWriteLock.tryLock(5, TimeUnit.SECONDS)) {
try {
// Got a lock! Start the rebuild if still out of date.
if (storeCache.expired(CachePill)) {
rebuildCache();
}
} finally {
cacheWriteLock.unlock();
}
}
}
}
Note that the storeCache.expired(CachePill) detects a stale cache which may be more than you are wanting but the concept here is the same, establish a write lock before updating the cache which will deny all read attempts until the rebuild is done. Also, manage multiple attempts at write in a loop of some sort or just drop out and let the read lock wait for access.
A read from the cache now looks like this:
public Object load(String id) throws Exception {
Store store = null;
// Make sure cache is fresh.
loadCache();
try {
// Establish a read lock so we do not attempt a read while teh cache is being updated.
cacheReadLock.lock();
store = storeCache.get(storeId);
} finally {
// Make sure the lock is cleared.
cacheReadLock.unlock();
}
return store;
}
The primary benefit of this form is that read access does not block other read access but everything stops cleanly during a rebuild - even other rebuilds.
You didn't say how complicated your structure is and how much concurrency / congestion you need. There are many ways to address your need.
If your data is simple, use a ConcurrentHashMap or similar to hold your data. Then just read and write in threads regardlessly.
Another alternative is to use actor model and put read/write on the same queue.
If all you need is to fill a read-only map which is initialized from database once requested, you could use any form of double-check locking which may be implemented in a number of ways. The easiest variant would be the following:
private volatile Map<T, V> cacheMap;
public void loadCacheMap() {
if (cacheMap == null) {
synchronized (this) {
if (cacheMap == null) {
cacheMap = retrieveParamCacheMap();
}
}
}
}
But I would personally prefer to avoid any form of synchronization here and just make sure that the initialization is done before any other thread can access it (for example in a form of init method in a DI container). In this case you would even avoid overhead of volatile.
EDIT: The answer works only when initial load is expected. In case of multiple updates, you could try to replace the tryLock by some other form of test and test-and-set, for example using something like this:
private final AtomicReference<CountDownLatch> sync =
new AtomicReference<>(new CountDownLatch(0));
private void loadCacheMap() {
CountDownLatch oldSync = sync.get();
if (oldSync.getCount() == 0) { // if nobody updating now
CountDownLatch newSync = new CountDownLatch(1);
if (sync.compareAndSet(oldSync, newSync)) {
cacheMap = retrieveParamCacheMap();
newSync.countDown();
return;
}
}
sync.get().await();
}

In Java, is it a security issue to expose the ID of a thread to arbitrary threads?

I have a class that can be instantiated only once for any given thread, through the use of a ThreadLocal, for instance:
public class MyClass {
private static final ThreadLocal<MyClass> classInstance =
new ThreadLocal<MyClass>() {
#Override protected MyClass initialValue() {
return new MyClass();
}
};
private MyClass() {
}
public static MyClass getInstance() {
return classInstance.get();
}
}
Now, I want these thread-specific instances to be accessed by another thread, so I end up with that kind of solution: https://stackoverflow.com/a/5180323/1768736
This solution is to use a Map (I would go for a ConcurrentHashMap), using as key a Thread-specific ID (for instance, a Map<long, MyClass>). I was considering to use Thread.currentThread().getId() as a key (providing some mechanisms to deal with the fact that a Thread ID can be reused).
But it means that I need to expose this Thread ID, for instance:
public class MyClass {
...
public long getId() {
//return the key associated with this MyClass instance in the Map.
//in my case, this would be the ID of the Thread
}
public static MyClass getMyClass(long threadId) {
//allow a Thread to access the MyClass instance of another Thread by providing an ID,
//in my case, that would be the Thread ID
}
}
So my question is: is it a bad practice to expose the ID of a Thread (the one returned by Thread.getId()), or do I have nothing to worry about? I don't know why, but my gut tells me I shouldn't do that.
Since Thread Id cannot be used to kill the thread (directly), it is safe to use. As applications can assign thread ids at the time of creating threads, I believe its usage is only to help you debug the application when you are looking at logs, thread-dumps, etc.
Also, as this link explains, it is not hard to get list of threads that are running in JVM. As long as you are aware of the fact that thread ids can get re-used after a thread has died, and your app's logic takes care of that, you should be alright.
I assume you are concerned about mobile-code security. It wouldn't appear to be the sort of thing that would introduce a vulnerability otherwise (I.D. reuse as a very long shot).
If you are worried about mobile-code security, then you want to avoid global and thread-global state anyway. You would anyway. Carrying on regardless...
From a security point of view Maps cause problems, particularly if you use non-values such as Thread for keys. A malicious subclass can pretend to be not equal to itself, equal to a different thread or acquire a Thread through Object.equals(Object). An IdentityHashMap would be ideal here, only you probably want a WeakHashMap. (I don't know why WeakHashMap uses key equality behaviour defined in Map rather than that in IdentityHashMap. A ConcurrentWeakIdentityHashMap (a "star map") would be excellent.)
Without modifying Thread, you probably want to introduce a key object that wraps thread giving the required behaviour.
final class Key {
private final int hash;
private final WeakReference<Thread> ref;
public Key(Thread thread) {
this.hash = System.identityHashCode(thread);
this.ref = new WeakReference<Thread>();
}
#Override public int hashCode() {
return hash;
}
#Override public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Key)) return false;
Key other = (Key)obj;
Thread thread = this.ref.get();
return thread != null && thread == other.ref.get();
}
}
(You will probably want to queue references so entries can be removed.)
Thread.getAllStackStraces has a security check, so untrusted code can't get them all. Similar calls limit execution to accessible thread groups.

Is there any way to know the progress of a EJB Asynchronous process?

I'm trying to get the percentage of the progress from a EJB Asynchronous process. Is this possible?
Does anyone have an idea how I could do this?
To get to know the progress of asynchronous processes is always tricky, especially if you don't know if they have actually started yet.
The best way I have found is to write another function that just gets the progress, so, if you have some unique id for each call, then update a hashmap with the current process. You may want to look at Concurrent Hashmap (http://download-llnw.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ConcurrentHashMap.html)
Then this other lookup function will just take the unique id, and return the progress back to the client.
If it hasn't been started, you can also return that, and ideally you may want to also be able to return any error messages that came up in the processing.
Then, when it has finished, and you returned the error message or success, then delete it from the hashmap, the client got the information, and that info won't change, so no point it keeping it around.
UPDATE:
In your interface make a new function
String progressDone(String id);
You will then refer to that synchronously, as it just goes out and comes right back, so it can look up the id in the hashmap and return either the percentage done or an error message.
But, this means that your actually worker function needs to every so often put information in the hashmap as to where it is, which is why I suggested using the concurrent hashmap, so that you don't have to worry about concurrent writes, and so locking considerations.
The solution I have found is an context object shared between asynchronous method and main thread. Here is an example:
Asynchronous job itself:
#Stateless
public class AsyncRunner implements AsyncRunnerLocal {
#Asynchronous
public Future<ResultObject> doWorkAsynchronous(WorkContext context) {
context.setRunning(true);
for (int i = 0; i < 100; i++) {
//Do the next iteration of your work here
context.setProgress(i);
}
context.setRunning(false);
return new AsyncResult(new ResultObject());
}
}
Shared context object. Important thing here is volatile keyword. Field values will be locally cached in each thread without it and progress will not be visible in main thread:
public class WorkContext {
//volatile is important!
private volatile Integer progress = 0;
private volatile boolean running = false;
//getters and setters are omitted
}
Usage example:
public class ProgressChecker {
#EJB
private AsyncRunnerLocal asyncRunner;
private WorkContext context;
private Future<ResultObject> future;
public void startJob() {
this.context = new WorkContext();
future = asyncRunner.doWorkAsynchronous(this.context);
//the job is running now
while (!future.isDone()) {
System.out.println("Progress: " + this.context.getProgress());
Thread.sleep(1000); //try catch is omitted
}
}
}
In EJB3.1 #Asynchronous method-calls can return java.util.concurrent.Future, this interface provides information boolean isCancelled() or boolean isDone(), but no information if the execution started. From my point of view, there is no way to get the information if the process started its execution via the EJB-Container in standard ways.

Categories