I have the following two methods in a class:
private MyDef myDef;
private FutureTask<MyDef> defFutureTask;
public synchronized void periodEviction() {
myDef = null;
}
public MyDef loadMyItems() {
// if it's not ready use a future - it will block until the results are ready
if (this.myDef == null) { // this will still not be thread safe
Callable<MyDef> callableDef = ()->{ return this.loadFromDatabase(); };
FutureTask<MyDef> defTask = new FutureTask<>(callableDef);
this.defFutureTask = defTask;
defFutureTask.run();
}
try {
// wait until's it's ready
this.myDef = this.qDefFuture.get();
} catch(InterruptedException e) {
log.error(this.getClass(), "Interrupted whilst getting future..");
} catch(ExecutionException e) {
log.error(this.getClass(), "Error when executing callable future");
}
return this.myDef;
}
I wanted to do the following:
1) Do a cache eviction using periodEviction() every one hour or so.
2) Otherwise, use the cached value when db loading is done.
I believe I have misunderstood Java future as I couldn't answer the question, "What happens when Thread A,B,and C all are calling loadMyItems() at the same time?"
So does this mean without something like an executor, this implementation is still not thread safe?
An even simpler approach is to not cache the object at all but just retain the Future.
private CompletableFuture<MyDef> defFuture;
public synchronized void periodEviction() {
// evict by triggering the request anew
defFuture = CompletableFuture.supplyAsync(this::loadFromDatabase);
}
public synchronized Optional<MyDef> loadMyItems() {
try {
return Optional.of(this.defFuture.get());
} catch(InterruptedException e) {
log.error(this.getClass(), "Interrupted whilst getting future..");
} catch(ExecutionException e) {
log.error(this.getClass(), "Error when executing callable future");
}
return Optional.empty();
}
With the caveat that this will trigger the database query every eviction period rather than on demand.
A super simple approach would be to declare loadMyItems as synchronized. But if the class has other methods that access myDef, you would have to declare those synchronized too. Sometimes this results in very coarse-grained locking and slower performance.
If you're looking for the cleanest/fastest code, instead of declaring periodEviction as synchronized, declare myDef as an AtomicReference:
private final AtomicReference<MyDef> myDef = new AtomicReference<>();
Then the body of periodEviction is:
synchronized (myDef) {
myDef.set(null);
}
And the body of loadMyItems is:
synchronized (myDef) {
if (myDef.get() == null) {
// perform initialization steps, ending with:
myDef.set(this.qDefFuture.get());
}
return myDef.get();
}
If many threads call loadMyItems at the same time, myDef will only ever be initialized once, and they will all get the same object returned (unless somehow a call to periodEviction snuck in the middle).
Related
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.
Is there a way to fail-fast as soon as multiple threads enter a method which is known not to be thread-safe?
Edit: Assuming a method is synchronized externally and not supposed to run concurrently. However, if external synchronization fails for some reason, it would be great to fail as soon as possible, thus avoiding subtle race-condition issues. Also, since the method normally runs in a single thread only, would be great to avoid/minimize synchronization penalty of the check.
The lock solutions, here, all add performance overhead, and I'm guessing you didn't make the class thread-safe for that reason. Java's collections are in the same situation, and they solved it with a "mod count" field in the class. It's not perfect (AtomicInteger would be better), and it's not guaranteed, but it catches most cases.
public class Foo {
private volatile int modCount = 0;
public void threadUnsafeMethod() {
int startModCount = ++modCount;
...
if (modCount != startModCount) { throw new ConcurrentModificationException(); }
}
}
If you just want to guard, you could do
public class Foo {
private final AtomicBoolean inThreadUnsafeMethod = new AtomicBoolean();
public void threadUnsafeMethod() {
if (!inThreadUnsafeMethod.compareAndSet(false, true) {
throw new ConcurrentModificationException();
}
try {
...
} finally {
inThreadUnsafeMethod.set(false);
}
}
}
With both, be very careful with handle reentrant calls correctly. this.otherThreadUnsafeMethod(); shouldn't fail.
Take a look at the ArrayList implementation (search for modCount).
I use an AtomicBoolean. First we have:
private final AtomicBoolean isExecuting = new AtomicBoolean();
Then, first thing we do in method not supposed to be executed concurrently:
if (isExecuting.getAndSet(true)) {
throw new UnsupportedOperationException();
}
Make sure that the one thread executing your method reset the flag on exit:
try {
// ... method implementation
}
finally {
isExecuting.set(false);
}
You may see two real world examples here and here.
You could create a lock and a wrapper method and then you can make each caller to invoke this method
private final Lock lock = new ReentrantLock();
public void wrapperMethod() {
if (!lock.tryLock())
throw new RuntimeException()
try {
threadUnsafeMethod();
}
finally {
lock.unlock();
}
}
With tryLock the caller tries to acquire the lock immediately. If the lock is already been acquired by some other caller it returns false and we throw an exception.
If you want to make each caller to fail fast in case of concurrent invocations, then it means that no two threads access the method concurrently. Otherwise, one of the two threads must have failed. This way you effectively add thread safety to your method.
An equivalent method using atomic longs but that remains a locking mechanism:
AtomicLong threadId = new AtomicLong(-1);
public void wrapperMethod() {
threadId.compareAndSet(-1, Thread.currentThread().getId());
if (threadId.get() != Thread.currentThread().getId())
throw new RuntimeException();
try {
threadUnsafeMethod();
}
finally {
threadId.set(-1);
}
}
Saying that, if you allow to use only a specific thread to run the code, this gives the idea for threads to run a contest. Then use only the winner for running the method:
AtomicLong winningThreadId = new AtomicLong(-1);
public void runContest() {
winningThreadId.compareAndSet(-1, Thread.currentThread().getId());
}
public void wrapperMethod() {
if (winningThreadId.get() != Thread.currentThread().getId())
throw new RuntimeException();
threadUnsafeMethod();
}
So every candidate thread runs the contest once and afterwards it uses the wrapper method.
I was going through an "JAX London 2011" presentation on "Modern Java Concurrency". Between the time duration 43:20 - 43:40, a person from the audience says the shutdown variable in the code below should have been declared as volatile and the presenters agree with it (and say that it was pointed out earlier as well, but they just didnt get to modify the presentation). The code in question is:
public abstract class QueueReaderTask implements Runnable {
private boolean shutdown = false;
protected BlockingQueue<WorkUnit<String>> lbq;
public void run() {
while (!shutdown) {
try {
WorkUnit<String> wu = lbq.poll(10, TimeUnit.MILLISECONDS);
if (wu != null) { doAction(wu.getWork()); }
} catch (InterruptedException e) {
shutdown = true;
}
}
}
public abstract void doAction(String msg);
public void setQueue(BlockingQueue<WorkUnit<String>> q) { lbq = q; }
}
My Question:
I dont think that shutdown should be declared volatile.
My reasoning is that shutdown being a member of a Runnable, each task/thread will have a distinct private copy of that variable. So, why make it volatile?
But since this was discussed in JAX 2011, I am assuming there were lots of expert Java developers in that audience. I dont think all of them would have missed this !
So, what am I missing ?
P.S:-
I can understand that a variable should be declared volatile if it was (potentially) shared by multiple threads, as in the Double-Checked-Locking pattern :
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
each task/thread will have a distinct private copy of that variable. So, why make it 'volatile' ?
You are correct if the shutdown boolean is only modified from within the QueueReaderTask instance. In that case shutdown is only being modified by the one thread and doesn't need to be volatile.
Frankly, the code looks strange to me. Why catch InterruptedException, set the shutdown boolean, and then loop around and exit. Why now just do the following? Why have the shutdown flag at all?
while (true) {
try {
WorkUnit<String> wu = lbq.poll(10, TimeUnit.MILLISECONDS);
if (wu != null) { doAction(wu.getWork()); }
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
Maybe there is extra code that was removed in the post? If not, I wonder if this was copy and pasted from a larger section of code where shutdown was set to true also in a method call.
P.S:- I can understand that a variable should be declared 'volatile' if it was (potentially) shared by multiple threads, as in the Double-Checked-Locking pattern :
Right. A typical pattern is that shutdown is modified from another thread which is telling the thread to stop processing. In that case it needs to be volatile.
This method notifes an event loop to start processing a message. However, if the event loop is already processing a message then, this method blocks until it receives a notification of completed event processing (which is triggered at the end of the event loop).
public void processEvent(EventMessage request) throws Exception {
System.out.println("processEvent");
if (processingEvent) {
synchronized (eventCompleted) {
System.out.println("processEvent: Wait for Event to completed");
eventCompleted.wait();
System.out.println("processEvent: Event completed");
}
}
myRequest = request;
processingEvent = true;
synchronized (eventReady) {
eventReady.notifyAll();
}
}
This works in client mode. If I switch to server mode and the time spent in the event loop processing the message is too quick, then the method above blocks forever waiting for the event to completed. For some reason the event complete notification is sent after the processingEvent check and before the eventCompleted.wait(). It makes no difference if I remove the output statements. I can not repeat the same problem in client mode.
Why does this only happen in server mode and what can I do to prevent this happening?
Here is the eventReady wait and eventCompleted notification:
public void run() {
try {
while (true) {
try {
synchronized (eventReady) {
eventReady.wait();
}
nx.processEvent(myRequest, myResultSet);
if (processingEvent > 0) {
notifyInterface.notifyEventComplete(myRequest);
}
} catch (InterruptedException e) {
throw e;
} catch (Exception e) {
notifyInterface.notifyException(e, myRequest);
} finally {
processingEvent--;
synchronized (eventCompleted) {
eventCompleted.notifyAll();
}
}
} // End of while loop
} catch (InterruptedException Ignore) {
} finally {
me = null;
}
Here is revised code which seems to work without the deadlock problem - which BTW happened in client mode randomely after about 300 events.
private BlockingQueue<EventMessage> queue = new SynchronousQueue<EventMessage>();
public void processEvent(EventMessage request) throws Exception {
System.out.println("processEvent");
queue.put(request);
}
public void run() {
try {
while (true) {
EventMessage request = null;
try {
request = queue.take();
processingEvent = true;
nx.processEvent(request, myResultSet);
notifyInterface.notifyEventComplete(request);
} catch (InterruptedException e) {
throw e;
} catch (Exception e) {
notifyInterface.notifyException(e, request);
} finally {
if (processingEvent) {
synchronized (eventCompleted) {
processingEvent = false;
eventCompleted.notifyAll();
}
}
}
} // End of while loop
} catch (InterruptedException Ignore) {
} finally {
me = null;
}
}
If you call notifyAll and no thread is wait()ing, the notify is lost.
The correct approach is to always change a state, inside the synchronized block, when calling notify() and always check that state, inside the synchronized block, before calling wait().
Also your use of processingEvent doesn't appear to be thread safe.
Can you provide the code which waits on eventReady and notifies eventCompleted?
Your program can happen to work if your speed up or slow down your application just right e.g. if you use -client, but if you use a different machine, JVM or JVM options it can fail.
There are a number of race conditions in your code. Even declaring processingEvent volatile or using an AtomicBoolean won't help. I would recommend using a SynchronousQueue which will block the event until the processer is ready for it. Something like:
private final BlockingQueue<Request> queue = new SynchronousQueue<Request>();
...
// this will block until the processor dequeues it
queue.put(request);
Then the event processor does:
while (!done) {
// this will block until an event is put-ed to the queue
Request request = queue.take();
process the event ...
}
Only one request will be processed at once and all of the synchronization, etc. will be handled by the SynchronousQueue.
If processingEvent isn't declared volatile or accessed from within a synchronized block then updates made by one thread may not become visible to other threads immediately. It's not clear from your code whether this is the case, though.
The "server" VM is optimised for speed (at the expense of startup time and memory usage) which could be the reason why you didn't encounter this problem when using the "client" VM.
There is a race condition in your code that may be exasperated by using the server VM, and if processingEvent is not volatile then perhaps certain optimizations made by the server VM or its environment are further influencing the problem.
The problem with your code (assuming this method is accessed by multiple threads concurrently) is that between your check of processingEvent and eventCompleted.wait(), another thread can already notify and (I assume) set processingEvent to false.
The simplest solution to your blocking problem is to not try to manage it yourself, and just let the JVM do it by using a shared lock (if you only want to process one event at a time). So you could just synchronize the entire method, for instance, and not worry about it.
A second simple solution is to use a SynchronousQueue (this is the type of situation it is designed for) for your event passing; or if you have more executing threads and want more than 1 element in the queue at a time then you can use an ArrayBlockingQueue instead. Eg:
private SynchronousQueue<EventMessage> queue = new SynchronousQueue<EventMessage>();
public void addEvent(EventMessage request) throws Exception
{
System.out.println("Adding event");
queue.put(request);
}
public void processNextEvent()
{
EventMessage request = queue.take();
processMyEvent(request);
}
// Your queue executing thread
public void run()
{
while(!terminated)
{
processNextEvent();
}
}
I have an application that every 15 minutes or so does a replication from a remote database. It just keeps the two repositories in sync. Once this replication is going it is not possible to do it again. I have setup the following structure but I'm not sure if it is the correct approach.
public class ReplicatorRunner {
private static Lock lock = new ReentrantLock();
public replicate() {
if (lock.tryLock()) {
try {
// long running process
} catch (Exception e) {
} finally {
lock.unlock();
}
} else {
throw new IllegalStateException("already replicating");
}
}
}
public class ReplicatorRunnerInvocator {
public void someMethod() {
try {
ReplicatorRunner replicator = new ReplicatorRunner();
replicator.replicate();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
The ReplicatorRunner is the class owning the method replicate which can only be run one at a time.
Edit.
I need the next call to fail (not block) if the method is already running on any instance.
This looks good. ReentrantLock.tryLock() will only give the lock to one thread, so synchronized is not necessary. It also prevents the blocking inherent in synchronization that you say is a requirement. ReentrantLock is Serializable, so should work across your cluster.
Go for it.
Change public replicate() to public synchronized replicate()
That way replicate will only ever allow access to one thread at a time. You'll also be able to delete the ReentrantLock and all associated code.
I ended up using the following:
public class ReplicatorRunner {
private static Semaphore lock = new Semaphore(1);
public replicate() {
if (lock.tryAcquire()) {
try {
// basic setup
Thread t = new Thread(new Runnable() {
public void run() {
try {
// long running process
} catch Exception (e) {
// handle the exceptions
} finally {
lock.release();
}
}
})
t.start();
} catch (Exception e) {
// in case something goes wrong
// before the thread starts
lock.release();
}
} else {
throw new IllegalStateException("already replicating");
}
}
}
public class ReplicatorRunnerInvocator {
public void someMethod() {
try {
ReplicatorRunner replicator = new ReplicatorRunner();
replicator.replicate();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
Without looking at the specifics of the ReentrantLock, it occurs to me that this prevention of multiple simultaneous replication routines will be limited to a single JVM instance.
If another instance of the class is kicked off in a separate JVM, then you might be in trouble.
Why not put a lock mechanism on the database? i.e. A row in a control table that is set to a value depicting whether or not the replication is busy running, and reset the value when the replication is finished.
take a look at the Semaphore class here or mark the method as synchronized
the thread executing the method at any given time owns a lock on it avoiding other threads to call the method until its execution ends.
Edit: if you want the other threads to fail, you could use a Lock, and test if the lock is avaible by the tryLock method.