AutomicReference compareAndSet usage - java

I have this class containing AccessTokenWithExpirationDate object wrapped in AutomicReference which I want it to be thread safe:
public class MyClass {
private AtomicReference<AccessTokenWithExpirationDate> accessTokenWithExpirationDate = new AtomicReference<>();
private AccessTokenWithExpirationDate putAccessTokenToCache(AccessTokenDto accessTokenDto) {
AccessTokenWithExpirationDate currentValue = this.accessTokenWithExpirationDate.get();
AccessTokenWithExpirationDate accessTokenWithExpirationDate
= new AccessTokenWithExpirationDate(accessTokenDto);
// if currentValue the same, update.
// if currentValue not the same - another thread already updated it. continue.
this.accessTokenWithExpirationDate.compareAndSet(currentValue, accessTokenWithExpirationDate);
return accessTokenWithExpirationDate;
}
private Optional<String> getAccessTokenFromCache() {
Optional<AccessTokenWithExpirationDate> accessTokenWithExpirationDate = Optional.ofNullable(this.accessTokenWithExpirationDate.get());
if (accessTokenWithExpirationDate.isPresent() && isTokenNotExpired(accessTokenWithExpirationDate.get())) {
return accessTokenWithExpirationDate
.map(AccessTokenWithExpirationDate::getTokenDto)
.map(AccessTokenDto::getAccessToken);
} else {
return Optional.empty();
}
}
}
lets say AccessTokenWithExpirationDate has initial value and now Thread1 arrives to method putAccessTokenToCache and run: accessTokenWithExpirationDate.compareAndSet,
and at the same time other threads try to run:
accessTokenWithExpirationDate.get() in getAccessTokenFromCache method,
will all threads calling get() will wait for compareAndSet() to finish to get the value after or not guarantied ?
if not, can the class be changed in a way that will allow it? some other use in AutomicReference that can promise that?
thank you !

Atomic values don't allow blocking. In some cases, this is good, but in your case (if understand it correctly), it is not. As i understand it, you want to cache an access token. If it doesn't exist yet, or is expired, you want a new token to be created. Ultimately, you want any caller accessing the cache to get a valid token.
You can achieve this in a performant manner using (the valid form of) double checked locking.
The basic pattern is:
private volatile Token _currentToken;
public Token getValidToken() {
Token token = _currentToken;
if(!isValidToken(token)) {
token = loadToken();
}
return token;
}
private synchronized Token loadToken() {
Token token = _currentToken;
if(!isValidToken(token)) {
token = // ... get valid token here ...
_currentToken = token;
}
return token;
}
private boolean isValidToken(Token token) {
// .. validate that token is not null or expired ...
}
for callers who call getValidToken() when there is already a valid token, they won't encounter any locking. note that reading a volatile incurs a similar performance hit without actually blocking, but this about the best you can get for concurrent code (without doing something with ThreadLocal and potentially an access token per thread).
for callers who encounter a missing or expired token, they will all block until a single caller gets a new, valid token.
note, there are probably good cache implementations in either google guava or apache commons which would handle this logic for you.

lets say AccessTokenWithExpirationDate has initial value and now Thread1 arrives to method putAccessTokenToCache() and run: accessTokenWithExpirationDate.compareAndSet(...), and at the same time other threads try to run: accessTokenWithExpirationDate.get() in getAccessTokenFromCache method, will all threads calling get() will wait for compareAndSet() to finish to get the value after or not guaranteed ?
Whenever accessTokenWithExpirationDate.get() is called, the guarantee is that the most recently set value of accessTokenWithExpirationDate is returned. Period. There is no locking. If the get is called before the set then the old value is returned. If the get is called after the set then the new value is returned.
if not, can the class be changed in a way that will allow it? some other use in AutomicReference that can promise that?
You can certainly add locking but I'm not sure what it buys you. Either the other threads call get() before or after the set() has completed. If you added locking then the same race conditions would happen but you would make the getting and setting of the value a lot more expensive. In your case, each thread has to cross memory barriers to ensure the correct publishing of the accessTokenWithExpirationDate value but there is no blocking.
Full locking is necessary when there are multiple values being updated in an object or if you need to ensure a single thread is accessing a resource at a time. If you need to set a single value, in your case accessTokenWithExpirationDate, then an AtomicReference is the right tool for the job.

Related

Thread safety for method that returns Mono based on mutable attribute in Java

In my Spring Boot application I have a component that is supposed to monitor the health status of another, external system. This component also offers a public method that reactive chains can subscribe to in order to wait for the external system to be up.
#Component
public class ExternalHealthChecker {
private static final Logger LOG = LoggerFactory.getLogger(ExternalHealthChecker.class);
private final WebClient externalSystemWebClient = WebClient.builder().build(); // config omitted
private volatile boolean isUp = true;
private volatile CompletableFuture<String> completeWhenUp = new CompletableFuture<>();
#Scheduled(cron = "0/10 * * ? * *")
private void checkExternalSystemHealth() {
webClient.get() //
.uri("/health") //
.retrieve() //
.bodyToMono(Void.class) //
.doOnError(this::handleHealthCheckError) //
.doOnSuccess(nothing -> this.handleHealthCheckSuccess()) //
.subscribe(); //
}
private void handleHealthCheckError(final Throwable error) {
if (this.isUp) {
LOG.error("External System is now DOWN. Health check failed: {}.", error.getMessage());
}
this.isUp = false;
}
private void handleHealthCheckSuccess() {
// the status changed from down -> up, which has to complete the future that might be currently waited on
if (!this.isUp) {
LOG.warn("External System is now UP again.");
this.isUp = true;
this.completeWhenUp.complete("UP");
this.completeWhenUp = new CompletableFuture<>();
}
}
public Mono<String> waitForExternalSystemUPStatus() {
if (this.isUp) {
LOG.info("External System is already UP!");
return Mono.empty();
} else {
LOG.warn("External System is DOWN. Requesting process can now wait for UP status!");
return Mono.fromFuture(completeWhenUp);
}
}
}
The method waitForExternalSystemUPStatus is public and may be called from many, different threads. The idea behind this is to provide some of the reactive flux chains in the application a method of pausing their processing until the external system is up. These chains cannot process their elements when the external system is down.
someFlux
.doOnNext(record -> LOG.info("Next element")
.delayUntil(record -> externalHealthChecker.waitForExternalSystemUPStatus())
... // starting processing
The issue here is that I can't really wrap my head around which part of this code needs to be synchronised. I think there should not be an issue with multiple threads calling waitForExternalSystemUPStatusat the same time, as this method is not writing anything. So I feel like this method does not need to be synchronised. However, the method annotated with #Scheduled will also run on it's own thread and will in-fact write the value of isUp and also potentially change the reference of completeWhenUpto a new, uncompleted future instance. I have marked these two mutable attributes with volatilebecause from reading about this keyword in Java it feels to me like it would help with guaranteeing that the threads reading these two values see the latest value. However, I am unsure if I also need to add synchronized keywords to part of the code. I am also unsure if the synchronized keyword plays well with reactor code, I have a hard time finding information on this. Maybe there is also a way of providing the functionality of the ExternalHealthCheckerin a more complete, reactive way, but I cannot think of any.
I'd strongly advise against this approach. The problem with threaded code like this is it becomes immensely difficult to follow & reason about. I think you'd at least need to synchronise the parts of handleHealthCheckSuccess() and waitForExternalSystemUPStatus() that reference your completeWhenUp field otherwise you could have a race hazard on your hands (only one writes to it, but it might be read out-of-order after that write) - but there could well be something else I'm missing, and if so it may show as one of these annoying "one in a million" type bugs that's almost impossible to pin down.
There should be a much more reliable & simple way of achieving this though. Instead of using the Spring scheduler, I'd create a flux when your ExternalHealthChecker component is created as follows:
healthCheckStream = Flux.interval(Duration.ofMinutes(10))
.flatMap(i ->
webClient.get().uri("/health")
.retrieve()
.bodyToMono(String.class)
.map(s -> true)
.onErrorResume(e -> Mono.just(false)))
.cache(1);
...where healthCheckStream is a field of type Flux<Boolean>. (Note it doesn't need to be volatile, as you'll never replace it so cross-thread worries don't apply - it's the same stream that will be updated with different results every 10 minutes based on the healthcheck status, whatever thread you'll access it from.)
This essentially creates a stream of healthcheck response values every 10 minutes, always caches the latest response, and turns it into a hot source. This means that the "nothing happens until you subscribe" doesn't apply in this case - the flux will start executing immediately, and any new subscribers that come in on any thread will always get the latest result, be that a pass or a fail. handleHealthCheckSuccess() and handleHealthCheckError(), isUp, and completeWhenUp are then all redundant, they can go - and then your waitForExternalSystemUPStatus() can just become a single line:
return healthCheckStream.filter(x -> x).next();
...then job done, you can call that from anywhere and you'll have a Mono that will only complete when the system is up.

Making static method Synchronized or Not

I have a webservice call to get an authorization token and use it for subsequent webservice calls. Now what we had done earlier was whenever we make any web service call, we first make the token web service and then make the call for actual web service.
Method to get the token is as shown below. Basically what this code does is call the webservice to get the token and using GSON parse the response and get the token.
public static String getAuthTicket() {
String authTicket = null;
HttpResponse httpResponse = getAuthResponse();
String body;
if (httpResponse.getStatusLine().getStatusCode() == 200) {
try {
body = IOUtils.toString(httpResponse.getEntity().getContent());
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
ResponseTicket responseTicket = gson.fromJson(body, ResponseTicket.class);
authTicket = responseTicket.getTicket();
} catch (UnsupportedOperationException e) {
LOGGER.error("UnsupportedOperationException : ",e);
} catch (IOException e) {
LOGGER.error("IO Exception : ",e);
}
}
return authTicket;
}
This has obviously led to performance issue. Hence the party who is providing the webservice to get the token has made the token valid for 30 minutes.
So in the above method what we are thinking is to put the token in cache along with the time and check if the current time - cache time is less than 30. If time is greater than 30 we will make service call to get token and update the token with timestamp in cache.
The only thing is I am fearing is about synchronization, so that I dont get corrupt authtoken due to race condition.
I am thinking to make this static method as synchronized. Do you think is there any other better way.
The answer is: it depends.
Race conditions occur when more than one thread is accessing shared data at the same point in time. So, when you would have code such as:
private final Map<X, Y> sharedCache = new HashMap<>();
public static getAuthTicket() {
if (! sharedCache.containsKey...) {
sharedCache.put(...
...
You would be subject to a race conditions - two threads could come in at the same time, and update that shared map at the very same time; leading to all kinds of problems.
When I get your code right - you would have something similar:
private static String cachedToken = null;
public static getAuthTicket() {
if (cachedToken == null || isTooOld(cachedToken)) {
cachedToken = getAuthTicketForReal();
}
return cachedToken;
}
You probably do not want that two threads call getAuthTicketForReal() in parallel.
So, yes, making that method synchronized is a valid approach.
Where: the real question is: is it sufficient to add that keyword? Given my code - the answer is yes. You simply want to avoid that this cache is setup "in parallel" by more than one thread.
Finally: in case you are worried about the performance impact of using synchronized here - simply forget about that. You are talking about a multi-second "network based" operation; so you absolutely do not worry about the milli second of overhead that synchronized might have (making up this number - the key thing: it is so small that it doesn't matter in the context of the operation you are doing).
Regarding your comment: of course, using synchronized means that the JVM will serialize calls to that method. This means when this method needs 1 minute to return - any other calls to that method will block for that 1 minute.
In that sense; it might be a good exercise to look into ways of writing up this method in a way that does not require synchronized on method level. For example by using data structures that can deal with multiple threads manipulating them.

Is it safe to use AtomicBoolean for database locking in Scala/Java?

I have an application where I want to ensure that a method is called at most once concurrently, say when updating user balance in a database.
I am thinking of using the following locking mechanism: (showing Scala code below, but should be similar with Java Lambdas):
object Foo{
val dbLocked = new java.util.concurrent.atomic.AtomicBoolean(false)
def usingAtoimcDB[T](f: => T):T = {
if (dbLocked.get) throw new Exception("db is locked")
dbLocked.set(true)
try f
finally dbLocked.set(false)
}
}
Is this safe to use when usingAtoimcDB may be called concurrently?
EDIT: The corrected code below, as pointed in this answer:
def usingAtoimcDB[T](f: => T):T = {
if(dbLocked.compareAndSet(false, true)) {
//db is now locked
try f
finally dbLocked.set(false)
} else {
//db is already locked
throw new Exception("db is locked")
}
}
EDIT 2:
Using a spinloop. Is this also ok?
def usingAtoimcDB[T](f: => T):T = {
while (!dbLocked.compareAndSet(false, true)) {Thread.sleep(1)}
try f
finally dbLocked.set(false)
}
EDIT3: Based on the answers and comments below, I am also considering using queues.
Inadvisable. You are requesting that the same pieco of code running in the same application instance on tha same server is the single point to do that transaction. There also is no provision to let this code stand-out. When you are retired, someone may start a second application instance or whatever.
Whereas a database commit/rollback is a quite simple and sure mechanism.
When you cannot write an integration (unit) test to ensure this sole point, then do not do it.
If you do it:
Revoke rights to the table modifications for the normal database user
Add a new database use who has sufficient right granted
And still: do not do it.
The code you posted above is not thread-safe, because you are not using an atomic check-and-set operation. Two threads can both be executing the if (dbLocked.get) statement at the same time and both get false as the answer, and then both will do dbLocked.set(true) and call f.
If you really want to use AtomicBoolean, then you must use compareAndSet as #leshkin already showed - this is an atomic operation that does the check and set in one go without the possibility of another thread doing the same thing at the same time, so that it is thread-safe.
You are using an AtomicBoolean as a lock here. There are classes in the standard Java library which are better suited (and specifically made) for this purpose; have a look at the package java.util.concurrent.locks.
You could for example use class ReentrantReadWriteLock, which combines two locks for reading and writing. The write lock is exclusive (when it's locked, nobody else can read or write); the read lock is shared (when it's locked, nobody can write, but others can read at the same time). This allows for there to be multiple readers concurrently, but only one writer at a time, possibly improving efficiency (it's not necessary to make reading an exclusive operation).
Example:
import java.util.concurrent.locks._
object Foo {
private val lock: ReadWriteLock = new ReentrantReadWriteLock
def doWriteOperation[T](f: => T): T = {
// Locks the write lock
lock.writeLock.lock()
try {
f
} finally {
lock.writeLock.unlock()
}
}
def doReadOperation[T](f: => T): T = {
// Locks the read lock
lock.readLock.lock()
try {
f
} finally {
lock.readLock.unlock()
}
}
}
Yes, it should work as espected. I would slightly modify your function using compareAndSet call.
compareAndSet method has the advantage to be an atomic operation - there are no race conditions and the value will be changed atomically.
def usingAtoimcDB[T](f: => T):T = {
if(dbLocked.compareAndSet(false, true)) {
//db is now locked
try f
finally dbLocked.set(false)
} else {
//db is already locked
throw new Exception("db is locked")
}
}

How to implement Java single Database thread

I have made a Java program that connects to a SQLite database using SQLite4Java.
I read from the serial port and write values to the database. This worked fine in the beginning, but now my program has grown and I have several threads. I have tried to handle that with a SQLiteQueue-variable that execute database operations with something like this:
public void insertTempValue(final SQLiteStatement stmt, final long logTime, final double tempValue)
{
if(checkQueue("insertTempValue(SQLiteStatement, long, double)", "Queue is not running!", false))
{
queue.execute(new SQLiteJob<Object>()
{
protected Object job(SQLiteConnection connection) throws SQLiteException
{
stmt.bind(1, logTime);
stmt.bind(2, tempValue);
stmt.step();
stmt.reset(true);
return null;
}
});
}
} // end insertTempValue(SQLiteStatement, long, double)
But now my SQLite-class can't execute the statements reporting :
DB[1][U]: disposing [INSERT INTO Temperatures VALUES (?,?)]DB[1][U] from alien thread
SQLiteDB$6#8afbefd: job exception com.almworks.sqlite4java.SQLiteException: [-92] statement is disposed
So the execution does not happen.
I have tried to figure out what's wrong and I think I need a Java wrapper that makes all the database operations calls from a single thread that the other threads go through.
Here is my problem I don't know how to implement this in a good way.
How can I make a method-call and ensure that it always runs from the same thread?
Put all your database access code into a package and make all the classes package private. Write one Runnable or Thread subclass with a run() method that runs a loop. The loop checks for queued information requests, and runs the appropriate database access code to find the information, putting the information into the request and marking the request complete before going back to the queue.
Client code queues data requests and waits for answers, perhaps by blocking until the request is marked complete.
Data requests would look something like this:
public class InsertTempValueRequest {
// This method is called from client threads before queueing
// Client thread queues this object after construction
public InsertTempValueRequest(
final long logTime,
final double tempValue
) {
this.logTime = logTime
this.tempValue = tempValue
}
// This method is called from client threads after queueing to check for completion
public isComplete() {
return isComplete;
}
// This method is called from the database thread after dequeuing this object
execute(
SQLiteConnection connection,
SQLiteStatement statement
) {
// execute the statement using logTime and tempValue member data, and commit
isComplete = true;
}
private volatile long logTime;
private volatile double tempValue;
private volatile boolean isComplete = false;
}
This will work, but I suspect there will be a lot of hassle in the implementation. I think you could also get by by using a lock that only permits one thread at a time to access the database, and also - this is the difference from your existing situation - beginning the access by creating the database resources - including statements - from scratch, and disposing of those resources before releasing the lock.
I found a solution to my problem. I have now implemented a wrapper-class that makes all operations with my older SQLite-class using an ExecutorService, inspired from Thread Executor Example and got the correct usage from Java Doc ExecutorService.

Long running method causing race condition

I'm relatively new with hibernate so please be gentle. I'm having an issue with a long running method (~2 min long) and changing the value of a status field on an object stored in the DB. The pseudo-code below should help explain my issue.
public foo(thing) {
if (thing.getStatus() == "ready") {
thing.setStatus("finished");
doSomethingAndTakeALongTime();
} else {
// Thing already has a status of finished. Send the user back a message.
}
}
The pseudo-code shouldn't take much explanation. I want doSomethingAndTakeALongTime() to run, but only if it has a status of "ready". My issue arises whenever it takes 2 minutes for doSomethingAndTakeALongTime() to finish and the change to thing's status field doesn't get persisted to the database until it leaves foo(). So another user can put in a request during those 2 minutes and the if statement will evaluate to true.
I've already tried updating the field and flushing the session manually, but it didn't seem to work. I'm not sure what to do from here and would appreciate any help.
PS: My hibernate session is managed by spring.
Basically you need to let it run in a separate Thread to make the method to return immediately. Else it will indeed block until the long running task is finished. You can pass the entity itself to the thread, so that it can update the status itself. Here's a basic kickoff example using a simple Thread.
public class Task extends Thread {
private Entity entity;
public Task(Entity entity) {
this.entity = entity;
}
public void run() {
entity.setStatus(Status.RUNNING);
// ...
// Long running task here.
// ...
entity.setStatus(Status.FINISHED);
}
}
and
public synchronized void foo(Entity entity) {
if (entity.getStatus() == Status.READY) {
new Task(entity).start();
} else {
// ...
}
}
With the Status in an enum you can even use a switch statement instead of an if/else.
switch (entity.getStatus()) {
case READY:
new Task(entity).start();
break;
case RUNNING:
// It is still running .. Have patience!
break;
case FINISHED:
// It is finished!
break;
}
For a more robust control of running threads, you may want to consider ExecutorService instead. Therewith you can control the maximum number of threads and specify a timeout.
What the method doSomethingAndTakeALongTime() is doing? is it for DB operation or just executing some business logic?
If its not doing any DB operation, and you got your status fine then you can persist the object before calling that method.
And if its doing some DB operation, then you need to wait for it. So, even if you put in thread you need to wait for that thread to complete (using thread.join() we can do that)
the thing is, before you persist you must have completed all operation based on you ORM object right? so try to optimized the logic for the method to get it executed before you persist.
thanks.

Categories