Usecase : Rotation of credentials for a datastore
What I want :
When updateCredentials is called, it will wait until it all threads are done fetching credentials (via the synchronize) to update the credentials to the new ones.
I DO NOT want calls to doSomeQuery making each other wait to fetch credentials. This object can be used in multiple threads and its a wasteful wait.
Is there a method / pattern to achieve this? The code sample below achieves item 1 but not item 2.
private Object credentialUpdate = new Object();
public void updateCredentials(String user, String pass) {
synchronize(credentialUpdate) {
this.user = user;
this.pass = pass;
}
}
public void doSomeQuery(String query) {
String curUser;
String curPass;
synchronize(credentialUpdate) {
curUser = this.user;
curPass;
}
// execute query
}
Use java.util.concurrent.locks.ReadWriteLock and its implementation ReentrantReadWriteLock. From the Javadoc:
A ReadWriteLock maintains a pair of associated locks, one for read-only operations and one for writing. The read lock may be held simultaneously by multiple reader threads, so long as there are no writers. The write lock is exclusive.
Related
What is the right way to solve following problem?
Writing a logic where at a same time 100 reader(Servlet requests) or one writer(Servlet requests) can be accessing critical section for one key in a map(Cache).
If writer comes into the picture in that case all reader should stop there progress and should restart once writer done with critical section processing(Re population cache element for same key).
I implemented one of the solution like in this question, where one instance of Resource class will be associated with single key.
class Resource {
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock rlock = lock.readLock();
private final Lock wlock = lock.writeLock();
void read() { ... /* caller has to hold the read lock */ ... }
void write() { ... /* caller has to hold the write lock */ ... }
Lock readLock() { return rlock; }
Lock writeLock() { return wlock; }
}
Previously I implemented simple logic using Semaphore where I have associated one semaphore instance with single key and used 100 permits for the same and if writer thread is coming into the picture in that case I consumed all remaining permits(drainPermits) and letting all permit free by all readers and putted writer thread in waiting queue. But it leads to starvation to writer.
Other thing I was thinking that using ConcurrentHashMap could solve it? As ConcurrentHashMap have key based locking internally(Segments).
You don't have to expose the locking to the user of the resource, however if you start implementing that pattern you soon discover that you may as well use a ConcurrentHashMap which is actually optimized well for synchronized access
class Resource {
private Cache<Key, Value> yourcache;
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock rlock = lock.readLock();
private final Lock wlock = lock.writeLock();
Value read(Key key) { try {
rlock.lock();
return yourcache.get(key)
} finally {
rlock.unlock();
}
}
void write(Key key) { ... /* similar pattern to above */ ... }
Lock readLock() { return rlock; } //don't expose these at all!
Lock writeLock() { return wlock; }//don't expose these at all!
}
I'm trying to multi thread a Result Set. I want to make sure whenever I call the next() within one of the many threads, all other threads are locked out. This is important , because if many threads call the next() method simultaneously, this will result in skipping the rows. Here is what I did
public class MainClass {
private static ResultSet rs;
public static void main (String [] args) {
Thread thread1 = new Thread(new Runnable() {
#Override
public void run() {
runWhile();
}});
Thread thread2 = new Thread(new Runnable() {
#Override
public void run() {
runWhile();
}});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.exit(0);
}
private static void runWhile () {
String username = null;
while ((username = getUsername()) != null) {
// Use username to complete my logic
}
}
/**
* This method locks ResultSet rs until the String username is retrieved.
* This prevents skipping the rows
* #return
* #throws SQLException
*/
private synchronized static String getUsername() throws SQLException {
if(rs.next()) {
return rs.getString(1).trim();
}
else
return null;
}
}
Is this a correct way of using synchronized. Does it lock the ResutSet and makes sure other thread do not interfere ?
Is this a good approach ?
JDBC objects shouldn't be shared between threads. That goes for Connections, Statements, and ResultSets. The best case here would be that the JDBC vendor follows the spec and does internal locking so that you can get by with this, in which case all the threads are still trying to acquire the same lock and only one can make progress at a time. This will be slower than using a single thread, because on top of doing the same work to read from the database there is extra overhead from managing all the threading.
(Locking done by the driver could be for the driver's benefit, so the provider doesn't have to deal with bug reports of race conditions caused by users misusing their software. That it does locking doesn't necessarily imply the software should actually be used by multiple threads.)
Multithreading works when threads can make progress concurrently, see Amdahl's Law. If you have a situation where you can read the ResultSet and use the results to create tasks which you submit to an ExecutorService (as Peter Lawrey recommends in a comment) then that would make more sense (as long as those tasks can work independently and don't have to wait on each other).
I will suggest to create the ResultSet, then copy all the data into a DTO (Data Transfer Object) or a DAO (Data Access Object). After having the data on the DTO or DAO, close your ResultSet, Statement and Connection.
A very simple structure to creat a DTO/DAO to store records in order, its fields, and parsing capabilities is this:
ArrayList<HashMap<String, Object>> table = new ArrayList<HashMap<String, Object>>();
HashMap<String, Object> record = new HashMap<String, Object>();
String field1 = "something";
Integer field2 = new Integer(45);
record.put("field1", field1);
record.put ("field2", field2);
table.add(record);
You may (and probably you should) automate and make the DTO/DAO flexible enough to use the same class in any table, without hard code or fixed names.
Remember that you will need to create a wrapper and the methods for storing/reading the data, and that these methods should be thread safe.
Keep in mind that this design only works if you have enough memory to store all the records of your ResultSet.
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();
}
How do I create a common variable between threads?
For example: Many threads sending a request to server to create users.
These users are saved in an ArrayList, but this ArrayList must be synchronized for all threads. How can I do it ?
Thanks all!
If you are going to access the list from multiple threads, you can use Collections to wrap it:
List<String> users = Collections.synchronizedList(new ArrayList<String>());
and then simply pass it in a constructor to the threads that will use it.
I would use an ExecutorService and submit tasks to it you want to perform. This way you don't need a synchronized collection (possibly don't need the collection at all)
However, you can do what you suggest by creating an ArrayList wrapped with a Collections.synchronizedList() and pass this as a reference to the thread before you start it.
What you could do is something like
// can be reused for other background tasks.
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
List<Future<User>> userFutures = new ArrayList<>();
for( users to create )
userFutures.add(executor.submit(new Callable<User>() {
public User call() {
return created user;
}
});
List<User> users = new ArrayList<>();
for(Future<User> userFuture: userFutures)
users.add(userFuture.get();
To expand on #Peter's answer, if you use an ExecutorService you can submit a Callable<User> which can return the User that was created by the task run in another thread.
Something like:
// create a thread pool with 10 background threads
ExecutorService threadPool = Executors.newFixedThreadPool(10);
List<Future<User>> futures = new ArrayList<Future<User>>();
for (String userName : userNamesToCreateCollection) {
futures.add(threadPool.submit(new MyCallable(userName)));
}
// once you submit all of the jobs, we shutdown the pool, current jobs still run
threadPool.shutdown();
// now we wait for the produced users
List<User> users = new ArrayList<User>();
for (Future<User> future : futures) {
// this waits for the job to complete and gets the User created
// it also throws some exceptions that need to be caught/logged
users.add(future.get());
}
...
private static class MyCallable implements Callable<User> {
private String userName;
public MyCallable(String userName) {
this.userName = userName;
}
public User call() {
// create the user...
return user;
}
}
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.