Java: Synchronization based on object value - java

I want to synchronize one method or one block based on input parameters.
So I have one API which has two inputs (let's say id1 and id2) of long type (could be primitive or wrapper) in post payload, which can be JSON. This API will be called by multiple threads at the same time or at different times randomly.
Now if the first API call has id1=1 and id2=1, and at the same time another API call has id1=1 and id2=1, it should wait for the first API call to finish processing before executing the second call. If the second API call has a different combination of values like id1=1 and id2=2, it should go through parallel without any wait time.
I don't mind creating a service method also which the API resource method can call, rather than handling directly at API resource method.
I'm using Spring boot Rest Controlller APIs.
**Edit**
I've already tried using map as suggested but this partially works. It waits for all input values, not just the same input values. Below is my code:
public static void main(String[] args) throws Exception {
ApplicationContext context = SpringApplication.run(Application.class, args);
AccountResource ar = context.getBean(AccountResource.class);
UID uid1 = new UID();
uid1.setFieldId(1);
uid1.setLetterFieldId(1);
UID uid2 = new UID();
uid2.setFieldId(2);
uid2.setLetterFieldId(2);
UID uid3 = new UID();
uid3.setFieldId(1);
uid3.setLetterFieldId(1);
Runnable r1 = new Runnable() {
#Override
public void run() {
while (true) {
ar.test(uid1);
}
}
};
Runnable r2 = new Runnable() {
#Override
public void run() {
while (true) {
ar.test(uid2);
}
}
};
Runnable r3 = new Runnable() {
#Override
public void run() {
while (true) {
ar.test(uid3);
}
}
};
Thread t1 = new Thread(r1);
t1.start();
Thread t2 = new Thread(r2);
t2.start();
Thread t3 = new Thread(r3);
t3.start();
}
#Path("v1/account")
#Service
public class AccountResource {
public void test(UID uid) {
uidFieldValidator.setUid(uid);
Object lock;
synchronized (map) {
lock = map.get(uid);
if (lock == null) {
map.put(uid, (lock = new Object()));
}
synchronized (lock) {
//some operation
}
}
}
}
package com.urman.hibernate.test;
import java.util.Objects;
public class UID {
private long letterFieldId;
private long fieldId;
private String value;
public long getLetterFieldId() {
return letterFieldId;
}
public void setLetterFieldId(long letterFieldId) {
this.letterFieldId = letterFieldId;
}
public long getFieldId() {
return fieldId;
}
public void setFieldId(long fieldId) {
this.fieldId = fieldId;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public int hashCode() {
return Objects.hash(fieldId, letterFieldId);
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
UID other = (UID) obj;
return fieldId == other.fieldId && letterFieldId == other.letterFieldId;
}
}

You need a collection of locks, which you can keep in a map and allocate as required. Here I assume that your id1 and id2 are Strings; adjust as appropriate.
Map<String,Object> lockMap = new HashMap<>();
:
void someMethod(String id1, String id2) {
Object lock;
synchronized (lockMap) {
lock = lockMap.get(id1+id2);
if (lock == null) lockMap.put(id1+id2, (lock = new Object()));
}
synchronized (lock) {
:
}
}
You need a little bit of 'global' synchronization for the map operations, or you could use one of the concurrent implementations. I used the base HashMap for simplicity of implementation.
After you've selected a lock, sync on it.

Related

Java FixedThreadPool with resources per thread?

This is a pseudocode version of my current working code:
public class DataTransformer {
private final boolean async = true;
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
public void modifyAsync(Data data) {
if (async) {
executorService.submit(new Runnable() {
#Override
public void run() {
modify(data);
}
});
} else {
modify(data);
}
}
// This should actually be a variable inside modify(byte[] data)
// But I reuse it to avoid reallocation
// This is no problem in this case
// Because whether or not async is true, only one thread is used
private final byte[] temp = new byte[1024];
private void modify(Data data) {
// Do work using temp
data.setReady(true); // Sets a volatile flag
}
}
Please read the comments. But now I want to use Executors.newFixedThreadPool(10) instead of Executors.newSingleThreadExecutor(). This is easily possible in my case by moving the field temp inside modify(Data data), such that each execution has it's own temp array. But that's not what I want to do because i want to reuse the array if possible. Instead I want for each of the 10 threads a temp array. What's the best way to achieve this?
As static variable is shared between all Threads, so you could declare as static. But if you want to use different values then either use Threadlocal or use different object.
With ThreadLocal you could do :
ThreadLocal<byte[]> value = ThreadLocal.withInitial(() -> new byte[1024]);
You could also use object like this:
public class Test {
public static void main(String[] args) {
try {
Test test = new Test();
test.test();
} catch (Exception e) {
e.printStackTrace();
}
}
class Control {
public volatile byte[] temp = "Hello World".getBytes();
}
final Control control = new Control();
class T1 implements Runnable {
#Override
public void run() {
String a = Arrays.toString(control.temp);
System.out.println(a);
}
}
class T2 implements Runnable {
#Override
public void run() {
String a = Arrays.toString(control.temp);
System.out.println(a);
}
}
private void test() {
T1 t1 = new T1();
T2 t2 = new T2();
new Thread(t1).start();
new Thread(t2).start();
}
}

How to sync a async operation in java

I am currently creating a database util class but my mongodb driver is async, my question now is how can I sync him? My current try looks something like this:
public boolean isBanIDFree(String banid) {
boolean value = false;
Thread thread = Thread.currentThread();
MongoCollection<Document> collection = database.getCollection("Bans");
collection.find(new Document("ID", banid)).first(new SingleResultCallback<Document>() {
#Override
public void onResult(Document result, Throwable t) {
if(result == null) {
value = true;
}
thread.notify();
}
});
try {
thread.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
return value;
}
but I can't edit the veriable value in the onResult Callback, how can I bypass this. i want to return a boolean and want the calling thread to wait until I got the response from the database
Variables used in anonymous classes must be effectively final.
That means you cannot assign them to something else, but you can call a setter on them.
So, you can do something like:
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) {
BooleanWrapper b = new BooleanWrapper();
CompletableFuture.runAsync(() -> b.setValue(true));
// ...
}
private static class BooleanWrapper {
private boolean value;
public boolean getValue() {
return value;
}
public void setValue(boolean value) {
this.value = value;
}
}
}

Java async servlet: Wait for a specific event

EDIT:
Edited the question in response to #maress answer below.
I have a web service in java (async enabled), which when called performs a call to another service asynchronously. In my Controller I have this:
private boolean receivedEvent = false;
private final Object SYNC = new Object();
public Callable<String> doStuff()
{
callSomeAsyncFunction();
return new Callable<String> ()
{
#Override
public String call() throws Exception {
synchronized (SYNC)
{
while (receivedEvent == false)
{
SYNC.wait();
}
receivedEvent = false;
System.out.println("RETURN");
return "ok";
}
}
};
}
public void onMyEvent(MyEvent event)
{
synchronized (SYNC)
{
receivedEvent = true;
System.out.println("RECEIVED");
SYNC.notify();
}
}
EDIT: The notification never gets through. System.out.println("RETURN") is never called. The events are being received ('RECEIVED' is shown).
Now all I want to do is wait for the callSomeAsyncFunction() to finish executing. When done, it triggers an event on the handler public void onMyEvent(MyEvent event).
Any suggestions? I am not even sure if my approach makes sense at all.
Synchronize always on a final instance.
private MyEvent myEvent;
private final Object SYNC = new Object();
public Callable<String> doStuff()
{
callSomeAsyncFunction();
return new Callable<String> ()
{
#Override
public String call() throws Exception {
synchronized (SYNC)
{
while (myEvent == null)
{
SYNC.wait();
}
return "ok";
}
}
};
}
public void onMyEvent(MyEvent event)
{
synchronized (SYNC)
{
myEvent = event;
SYNC.notifyAll();
}
}

Concurrent tests: test case scenario automatization

Task definition: I need to test custom concurrent collection or some container which manipulates with collections in concurrent environment. More precisely - I've read-API and write-API. I should test if there is any scenarios where I can get inconsistent data.
Problem: All concurrent test frameworks (like MultiThreadedTC, look at MultiThreadedTc section of my question) just provides you an ability to control the asynchronous code execution sequence. I mean you should suppose a critical scenarios by your own.
Broad question: Is there frameworks that can take annotations like #SharedResource, #readAPI, #writeAPI and check if your data will always be consistent? Is that impossible or I just leak a startup idea?
Annotation: If there is no such framework, but you find the idea attractive, you are welcome to contact me or propose your ideas.
Narrow question: I'm new in concurrency. So can you suggest which scenarios should I test in the code below? (look at PeerContainer class)
PeerContainer:
public class PeersContainer {
public class DaemonThreadFactory implements ThreadFactory {
private int counter = 1;
private final String prefix = "Daemon";
#Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, prefix + "-" + counter);
thread.setDaemon(true);
counter++;
return thread;
}
}
private static class CacheCleaner implements Runnable {
private final Cache<Long, BlockingDeque<Peer>> cache;
public CacheCleaner(Cache<Long, BlockingDeque<Peer>> cache) {
this.cache = cache;
Thread.currentThread().setDaemon(true);
}
#Override
public void run() {
cache.cleanUp();
}
}
private final static int MAX_CACHE_SIZE = 100;
private final static int STRIPES_AMOUNT = 10;
private final static int PEER_ACCESS_TIMEOUT_MIN = 30;
private final static int CACHE_CLEAN_FREQUENCY_MIN = 1;
private final static PeersContainer INSTANCE;
private final Cache<Long, BlockingDeque<Peer>> peers = CacheBuilder.newBuilder()
.maximumSize(MAX_CACHE_SIZE)
.expireAfterWrite(PEER_ACCESS_TIMEOUT_MIN, TimeUnit.MINUTES)
.removalListener(new RemovalListener<Long, BlockingDeque<Peer>>() {
public void onRemoval(RemovalNotification<Long, BlockingDeque<Peer>> removal) {
if (removal.getCause() == RemovalCause.EXPIRED) {
for (Peer peer : removal.getValue()) {
peer.sendLogoutResponse(peer);
}
}
}
})
.build();
private final Striped<Lock> stripes = Striped.lock(STRIPES_AMOUNT);
private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1, new DaemonThreadFactory());
private PeersContainer() {
scheduledExecutorService.schedule(new CacheCleaner(peers), CACHE_CLEAN_FREQUENCY_MIN, TimeUnit.MINUTES);
}
static {
INSTANCE = new PeersContainer();
}
public static PeersContainer getInstance() {
return INSTANCE;
}
private final Cache<Long, UserAuthorities> authToRestore = CacheBuilder.newBuilder()
.maximumSize(MAX_CACHE_SIZE)
.expireAfterWrite(PEER_ACCESS_TIMEOUT_MIN, TimeUnit.MINUTES)
.build();
public Collection<Peer> getPeers(long sessionId) {
return Collections.unmodifiableCollection(peers.getIfPresent(sessionId));
}
public Collection<Peer> getAllPeers() {
BlockingDeque<Peer> result = new LinkedBlockingDeque<Peer>();
for (BlockingDeque<Peer> deque : peers.asMap().values()) {
result.addAll(deque);
}
return Collections.unmodifiableCollection(result);
}
public boolean addPeer(Peer peer) {
long key = peer.getSessionId();
Lock lock = stripes.get(key);
lock.lock();
try {
BlockingDeque<Peer> userPeers = peers.getIfPresent(key);
if (userPeers == null) {
userPeers = new LinkedBlockingDeque<Peer>();
peers.put(key, userPeers);
}
UserAuthorities authorities = restoreSession(key);
if (authorities != null) {
peer.setAuthorities(authorities);
}
return userPeers.offer(peer);
} finally {
lock.unlock();
}
}
public void removePeer(Peer peer) {
long sessionId = peer.getSessionId();
Lock lock = stripes.get(sessionId);
lock.lock();
try {
BlockingDeque<Peer> userPeers = peers.getIfPresent(sessionId);
if (userPeers != null && !userPeers.isEmpty()) {
UserAuthorities authorities = userPeers.getFirst().getAuthorities();
authToRestore.put(sessionId, authorities);
userPeers.remove(peer);
}
} finally {
lock.unlock();
}
}
void removePeers(long sessionId) {
Lock lock = stripes.get(sessionId);
lock.lock();
try {
peers.invalidate(sessionId);
authToRestore.invalidate(sessionId);
} finally {
lock.unlock();
}
}
private UserAuthorities restoreSession(long sessionId) {
BlockingDeque<Peer> activePeers = peers.getIfPresent(sessionId);
return (activePeers != null && !activePeers.isEmpty()) ? activePeers.getFirst().getAuthorities() : authToRestore.getIfPresent(sessionId);
}
public void resetAccessedTimeout(long sessionId) {
Lock lock = stripes.get(sessionId);
lock.lock();
try {
BlockingDeque<Peer> deque = peers.getIfPresent(sessionId);
peers.invalidate(sessionId);
peers.put(sessionId, deque);
} finally {
lock.unlock();
}
}
}
MultiThreadedTC test case sample: [optional section of question]
public class ProducerConsumerTest extends MultithreadedTestCase {
private LinkedTransferQueue<String> queue;
#Override
public void initialize() {
super.initialize();
queue = new LinkedTransferQueue<String>();
}
public void thread1() throws InterruptedException {
String ret = queue.take();
}
public void thread2() throws InterruptedException {
waitForTick(1);
String ret = queue.take();
}
public void thread3() {
waitForTick(1);
waitForTick(2);
queue.put("Event 1");
queue.put("Event 2");
}
#Override
public void finish() {
super.finish();
assertEquals(true, queue.size() == 0);
}
}
Sounds like a job for static analysis, not testing, unless you have time to run multiple trillions of test cases. You pretty much can't test multithreaded behaviour - test behaviour in a single thread, then prove the abscence of threading bugs.
Try:
http://www.contemplateltd.com/threadsafe
http://checkthread.org/

Why I am getting deadlock

I cannot understand why I am getting deadlock in this simple sample.What is wrong with it?
public static void main(String[] args) {
Object data = null;
new Thread(new Producer(data)).start();
new Thread(new Consumer(data)).start();
}
}
class Producer implements Runnable {
private Object data;
public Producer(Object data) {
this.data = data;
}
#Override
public void run() {
while (true) {
while (data != null) {}
data = new Object();
System.out.println("put");
}
}
}
class Consumer implements Runnable {
private Object data;
public Consumer(Object data) {
this.data = data;
}
#Override
public void run() {
while (true) {
while (data == null) { }
data = null;
System.out.println("get");
}
}
There are two problems.
1: You have two separate Runnables that each have their own private internal member named data. Changes made to one aren't visible to the other. If you want to pass data between two threads, you need to store it in a common place where they both access it. You also need to either synchronize around the accesses or make the reference volatile.
2: Your checks seem to be inverted. You probably want to null it when it's not null, and create one when it is null? Its tough to tell what you want it to actually do there! :)
public static volatile Object data;
public static void main(String[] args) {
data = null;
new Thread(new Producer(data)).start();
new Thread(new Consumer(data)).start();
}
}
class Producer implements Runnable {
public Producer(Object data) {
this.data = data;
}
#Override
public void run() {
while (true) {
while (data == null) {}
data = new Object();
System.out.println("put");
}
}
}
class Consumer implements Runnable {
public Consumer(Object data) {
this.data = data;
}
#Override
public void run() {
while (true) {
while (data != null) { }
data = null;
System.out.println("get");
}
}
(Also this isn't really an example classically what we'd define as a deadlock, where two threads can't proceed because they both want locks the other has. There are no locks here. This is an example of two infinite loops that just don't do anything.)
Each instance has its own data field.
The consumer never sees the producer's changes.
The consumer and producer have separate data fields, so the consumer will never get any data to consume.
Also, spinlocking a consumer/producer on a field isn't generally a good idea, you're much better off using mutexes or semaphores to signal the availability of data / the possibility to publish. If this is more than a test in the search of knowledge, you should really read up on how to use those two.
When your produced "produces", all it does is points its own data reference to the new object, and the consumer has no way of knowing what happened. What you can do instead is make another class
class Data {
private Object data = null;
synchronized void set( Object data ){ this.data = data; }
synchronized Object get(){ return data; }
}
Then in your main do
Data data = new Data();
Pass the 'Data' object to the consumer and producer, and use the get/set methods instead of assignment.
That way, both consumer and producer will be pointing to the same Data object and when the producer produces or the consumer consumes, they will be changing the reference in the Data object, which they are sharing.
I think this should do what you intend (it is still bad code):
public class Example {
public static void main(String[] args) {
Consumer consumer = new Consumer();
new Thread(new Producer(consumer)).start();
new Thread(consumer).start();
}
}
class Producer implements Runnable {
private final Consumer consumer;
public Producer(Consumer consumer) {
this.consumer = consumer;
}
#Override
public void run() {
while (true) {
while (consumer.data != null) {}
consumer.data = new Object();
System.out.println("put");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
public volatile Object data;
#Override
public void run() {
while (true) {
while (data == null) {}
data = null;
System.out.println("get");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
I think you should focus on the basics of Java, before you go for advanced topics such as parallel programming as the main error in you example (separate data fields) is very basic.

Categories

Resources