Java synchronization depending on method parameter - java

how can I provide synchronization upon method parameter values?
All method calls using the 'same' parameter value A should be synchronized. A method call with a different parameter value e.g. B can access, even when calls with A are already waiting. The next concurrent call for B must wait also for the first B to be released.
My use case: I want to synchronize the access to JPA entities on ID level but want to avoid pessimistic locking because I need kind of a queue. The 'key' for locking is intended to be the entity ID - which is in fact of the type Java Long.
protected void entityLockedAccess(SomeEntity myEntity) {
//getId() returns different Long objects so the lock does not work
synchronized (myEntity.getId()) {
//the critical section ...
}
}
I read about lock objects but I am not sure how they would suit in my case.
On the top level I want to manage a specific REST call to my application which executes critical code.
Thanks,
Chris

As far as I understood you basically want a different, unique lock for each of your SomeEntity IDs.
You could realize this with a Map<Integer, Object>.
You simply map each ID to an object. Should there already be an object, you reuse it. This could look something like this:
static Map<Integer, Object> locks = new ConcurrentHashMap<>();
public static void main(String[] args)
{
int i1 = 1;
int i2 = 2;
foo(i1);
foo(i1);
foo(i2);
}
public static void foo(int o)
{
synchronized (locks.computeIfAbsent(o, k -> new Object()))
{
// computation
}
}
This will create 2 lock objects in the map as the object for i1 is reused in the second foo(i1) call.

Objects which are pooled and potentially reused should not be used for synchronization. If they are, it can cause unrelated threads to deadlock with unhelpful stacktraces.
Specifically, String literals, and boxed primitives such as Integers should NOT be used as lock objects because they are pooled and reused.
The story is even worse for Boolean objects because there are only two instances of Boolean, Boolean.TRUE and Boolean.FALSE and every class that uses a Boolean will be referring to one of the two.
I read about lock objects but I am not sure how they would suit in my
case. On the top level I want to manage a specific REST call to my
application which executes critical code.
You DB will take care for concurrent writes and other transactional issues.
All you need to do is use Transactions.
I would also recommend you to go through the classical problems (DIRTY READs NON Repeatable reads). You can also use Optimistic Locking for

The problem is that you simply should not synchronize on values (for example strings, or Integer objects).
Meaning: you would need to define some special EntityId class here, and of course, all "data" that uses the same ID would somehow need to be using the same EntityId object then.

private static final Set<Integer> lockedIds = new HashSet<>();
private void lock(Integer id) throws InterruptedException {
synchronized (lockedIds) {
while (!lockedIds.add(id)) {
lockedIds.wait();
}
}
}
private void unlock(Integer id) {
synchronized (lockedIds) {
lockedIds.remove(id);
lockedIds.notifyAll();
}
}
public void entityLockedAccess(SomeEntity myEntity) throws InterruptedException {
try {
lock(myEntity.getId());
//Put your code here.
//For different ids it is executed in parallel.
//For equal ids it is executed synchronously.
} finally {
unlock(myEntity.getId());
}
}
id can be not only an 'Integer' but any class with correctly overridden 'equals' and 'hashCode' methods.
try-finally - is very important - you must guarantee to unlock waiting threads after your operation even if your operation threw exception.
It will not work if your back-end is distributed across multiple servers/JVMs.

Just use this class:
(and the map will NOT increase in size over time)
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
public class SameKeySynchronizer<T> {
private final ConcurrentHashMap<T, Object> sameKeyTasks = new ConcurrentHashMap<>();
public void serializeSameKeys(T key, Consumer<T> keyConsumer) {
// This map will never be filled (because function returns null), it is only used for synchronization purposes for the same key
sameKeyTasks.computeIfAbsent(key, inputArgumentKey -> acceptReturningNull(inputArgumentKey, keyConsumer));
}
private Object acceptReturningNull(T inputArgumentKey, Consumer<T> keyConsumer) {
keyConsumer.accept(inputArgumentKey);
return null;
}
}
Like in this test:
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class SameKeySynchronizerTest {
private static final boolean SHOW_FAILING_TEST = false;
#Test
void sameKeysAreNotExecutedParallel() throws InterruptedException {
TestService testService = new TestService();
TestServiceThread testServiceThread1 = new TestServiceThread(testService, "a");
TestServiceThread testServiceThread2 = new TestServiceThread(testService, "a");
testServiceThread1.start();
testServiceThread2.start();
testServiceThread1.join();
testServiceThread2.join();
Assertions.assertFalse(testService.sameKeyInProgressSimultaneously);
}
#Test
void differentKeysAreExecutedParallel() throws InterruptedException {
TestService testService = new TestService();
TestServiceThread testServiceThread1 = new TestServiceThread(testService, "a");
TestServiceThread testServiceThread2 = new TestServiceThread(testService, "b");
testServiceThread1.start();
testServiceThread2.start();
testServiceThread1.join();
testServiceThread2.join();
Assertions.assertFalse(testService.sameKeyInProgressSimultaneously);
Assertions.assertTrue(testService.differentKeysInProgressSimultaneously);
}
private class TestServiceThread extends Thread {
TestService testService;
String key;
TestServiceThread(TestService testService, String key) {
this.testService = testService;
this.key = key;
}
#Override
public void run() {
testService.process(key);
}
}
private class TestService {
private final SameKeySynchronizer<String> sameKeySynchronizer = new SameKeySynchronizer<>();
private Set<String> keysInProgress = ConcurrentHashMap.newKeySet();
private boolean sameKeyInProgressSimultaneously = false;
private boolean differentKeysInProgressSimultaneously = false;
void process(String key) {
if (SHOW_FAILING_TEST) {
processInternal(key);
} else {
sameKeySynchronizer.serializeSameKeys(key, inputArgumentKey -> processInternal(inputArgumentKey));
}
}
#SuppressWarnings("MagicNumber")
private void processInternal(String key) {
try {
boolean keyInProgress = !keysInProgress.add(key);
if (keyInProgress) {
sameKeyInProgressSimultaneously = true;
}
try {
int sleepTimeInMillis = 100;
for (long elapsedTimeInMillis = 0; elapsedTimeInMillis < 1000; elapsedTimeInMillis += sleepTimeInMillis) {
Thread.sleep(sleepTimeInMillis);
if (keysInProgress.size() > 1) {
differentKeysInProgressSimultaneously = true;
}
}
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
} finally {
keysInProgress.remove(key);
}
}
}
}

Related

JAVA - program that asigns a specific variable to every new object created

I have an abstract class called Worker which is extended by two subclasses, PermanentWorker and NonPermanentWorker. All these classes inherit various properties, one of those being wCode, an int that should be given to every new worker automatically when it is created. For example, the first worker should have wCode=XXX1, the second wCode=XXX2 etc. (XXX being some three digit number like 123, doesnt matter)
The question is, how do I check if an object has already been created (or not) so that it will receive the appropriate code? Like it's obvious that an if-else command block should be used, but how exactly? My original approach was something like this:
public abstract class Worker
{
private int wCode;
[....]
public Worker() {
int i=1;
if(....) wCode = 1230 + i;
i++; }
public abstract class Worker {
private static int lastId = 0;
protected final int wCode;
public Worker() {
wCode = lastId++;
}
}
You need a static field which will be your ID generator. wCode is going to be initialized in the worker class and you don't have to worry about an ID being already used because it won't happen.
If you really need to keep track of Workers and retrieve them, you can store them in a Set<Worker> static field or a Map<Integer, Worker> and add them in the constructor.
e.g.
public class Worker {
// rest of the code omitted
// workers set
private static Set<Worker> workersSet = new HashSet<>();
// or workers map
private static Map<Integer, Worker> workersMap = new HashMap<>();
// add the instance to the set or map
public Worker() {
// id part omitted
workersSet.add(this);
// or
workersMap.add(this.wCode, this);
}
// expose the collections as read-only to outside world
public static Set<Worker> workers() {
return Collections.unmodifiableSet(workersSet);
}
public static Worker getWorker(int wCode) {
return workersSet.stream()
.filter(w -> w.wCode = wCode)
.findAny()
// or drop the orElse part and make the method return Optional<Worker>
.orElse(null);
// for map counterpart, it's easier:
// return workersMap.get(wCode);
}
}
An easier implementation would be with an List/ArrayList instead of Set/HashSet and the retrieval would be as easy as workersList.get(wCode); since the Worker with wCode set to 50 will be found at index 50 in that list.
You must create this variable in the worker class :
public abstract class Worker
{
private static int idGenerator;
private int id;
}
When you create a new worker give it an automatic ID in the constructor :
public Worker () {
this.id = idGenerator++;
}
That way you are guaranteed that every new worker created gets their own ID.

Use CAS instead of synchronized

Recently, I came across a situation when creating a factory producing reusable instances.
public class Factory {
private static final int REUSABLE_TIMES_LIMIT = 10;
private static Product instance = new Product();
private static int getTimes;
public static synchronized Product getInstance() {
if (++getTimes >= REUSABLE_TIMES_LIMIT) {
return nextInstance();
}
return instance;
}
public static synchronized Product nextInstance() {
getTimes = 0;
instance = new Product();
return instance;
}
}
Since getInstance() and nextInstance() might both be invoked concurrently by different threads in my case, I choose to add synchronized key words before each of them. However, synchronized is too heavy when lots of threads comes to the method, so I'd like to rewrite this class based on CAS, i.e. those classes in the package of java.util.concurrent.atomic. Unfortunately, I didn't figure out a proper way to arrange my code with two atomic variables, namely instance and getTimes, in the same time. Will someone show me how to correctly use CAS instead of synchronized without causing race condition in this situation? Thanks in advance :)
The one possible option is to use one AtomicReference instead of two. This will make your state consistent regardless of the code compexity.
public static class ProductStorage {
private Product product;
private int getTimes;
public ProductStorage(Product product, int getTimes) {
this.product = product;
this.getTimes = getTimes;
}
}
public static class Factory {
private static final int REUSABLE_TIMES_LIMIT = 10;
private static AtomicReference<ProductStorage> instance = new AtomicReference<>(
new ProductStorage(new Product(), 0)
);
public static Product getInstance() {
ProductStorage current;
for(;;) {
current = instance.get();
if(current.getTimes >= REUSABLE_TIMES_LIMIT) {
instance.compareAndSet(current, new ProductStorage(new Product(), 0));
continue;
}
if(current.getTimes < REUSABLE_TIMES_LIMIT) {
if(instance.compareAndSet(current, new ProductStorage(current.product, current.getTimes + 1))) {
return current.product;
}
}
}
}
}
The first thing you may mention is that new object is always allocated in that case. But remember that most of lock-free algorithms do that and it's not a problem. Allocation in java is fast and costs a few nanoseconds. You may also see similar solution in Martin Thompson's blog. The code is here. On my machine lock-free solution runs 3-4 times fastrer.
If may want to go with two atomics, but that will make counting of getTimes hard.

How is this "container Design Pattern" called?

While creating my app. architecture I faced the need for one structure, that will be described below.
I'm pretty sure, that there is a well known design pattern with the same functionality, because I think that problem, for which I develop it is really common.
I write my own implementation of this, but I always try to use "build in language" implementations of patterns, so - please help me to name this construction.
The idea is close to reader-writer pattern. We have a "container" in which we can add Objects by the key (). And also we can get this objects by keys, removing it from container.
So, the implemented class should have two methods:
void putObject(Key key, Object object);
Object getObject(Key key); // remove <Key,Object> from container.
The next is most interesting.
This container should work in multi-threading environment as follows:
If there is no object associated with key, while calling get(Key
key) method the caller thread should WAIT for the object in this
container.
When another thread will call putObject(Key key, Object object)
method it should check if there is some thread that wait exactly for
this object, and if it is - then signal and wake up the thread that
waits.
I think that it is common structure, does it have "official" name?
My Java implementation of this pattern:
private static interface BlackBox {
public void addObject(IdObject object);
public IdObject getObject(ObjectId id);
}
private static class BlackBoxImpl implements BlackBox {
private final Lock conditionLock = new ReentrantLock();
private final Map<ObjectId, IdObject> savedObjects;
private final Map<ObjectId, Condition> waitingConditions;
public BlackBoxImpl() {
this.savedObjects = new ConcurrentHashMap<ObjectId, IdObject>(20);
this.waitingConditions = new ConcurrentHashMap<ObjectId, Condition>(20);
}
#Override
public void addObject(IdObject object) {
savedObjects.put(object.getId(), object);
if (waitingConditions.containsKey(object.getId())) {
Condition waitCondition = waitingConditions.get(object.getId());
conditionLock.lock();
waitCondition.signal();
conditionLock.unlock();
}
}
#Override
public IdObject getObject(ObjectId id) {
if (savedObjects.containsKey(id)) {
return savedObjects.get(id);
} else {
conditionLock.lock();
Condition waitCondition = conditionLock.newCondition();
waitingConditions.put(id, waitCondition);
waitCondition.awaitUninterruptibly();
conditionLock.unlock();
return savedObjects.get(id);
}
}
}
private static interface IdObject {
public ObjectId getId();
}
private static class IdObjectImpl implements IdObject {
protected final ObjectId id;
public IdObjectImpl(ObjectId id) {
this.id = id;
}
#Override
public ObjectId getId() {
return id;
}
}
private static interface ObjectId {
}
private static class ObjectIdImpl implements ObjectId {
}
I would probably use something like a
ConcurrentMap<K,BlockingQue<V>>.
Use the concurrent methods of the Map to add the pair. Take from your queue for the value. Use an ArrayBlockingQue(1).
Something like this perhaps:
static class MultiQueue<K, V> {
// The base structure.
final ConcurrentMap<K, BlockingQueue<V>> queues = new ConcurrentHashMap<>();
/**
* Put an item in the structure.
*
* The entry in the map will be created if no entry is currently there.
*
* The value will then be posted to the queue.
*/
public void put(K k, V v) throws InterruptedException {
// Make it if not present.
ensurePresence(k).put(v);
}
/**
* Get an item from the structure.
*
* The entry in the map will be created if no entry is currently there.
*
* The value will then be taken from the queue.
*/
public void get(K k) throws InterruptedException {
// Make it if not present - and wait for it.
ensurePresence(k).take();
}
private BlockingQueue<V> ensurePresence(K k) {
// Make it if not present.
return queues.computeIfAbsent(k, v -> new ArrayBlockingQueue(1));
}
}
Looking at your design, to me what you are describing
We have a "container" in which we can add Objects by the key (). And also we can get this objects by keys, removing it from container.
This container should work in multi-threading environment
is close to concurrent Object pool. It uses a set of initialized objects kept ready to use. A client of the pool will request an object from the pool and perform operations on the returned object.
The only real difference I see is that you are getting the objects based on your own criteria.

Accessing private access variable data from different class

I have this Thread inside my Project which runs continously accepting new symbols
public class StreamThread extends Thread {
private Set<String> allSymbolSet = new HashSet<String>(Arrays.asList("USBC", "TCSD", "PCLJ"));
private PriorityBlockingQueue<String> priorityBlocking = new PriorityBlockingQueue<String>();
public void addSymbols(String str) {
if (str != null) {
priorityBlocking.add(str);
}
}
public void run() {
while (true) {
try {
while (priorityBlocking.peek() != null) {
String symbol = priorityBlocking.poll();
allSymbolSet.add(symbol);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
my question is , i want to access the variable allSymbolSet from another class
what will be the best approach to get access to this variable named allSymbolSet from anoter class , for this i have two choices
modify the access specifier of allSymbolSet from private to default .
Write a get Method which is supoused to return the Set
Please suggest me , what will be the good approach in this case ??
Best approach would be the getter method AND synchronize the access to the object allSymbolSet, something like this:
public Set<String> getAllSymbolSet() {
synchronized(allSymbolSet) {
return allSymbolSet;
}
}
and also synchronize the access to allSymbolSet inside your thread.
A few comments:
If you make the set non-private, some code could modify it (by mistake or on purpose) which could result in inconsistent behaviour in your StreamThread class. Don't do that.
Providing a simple getter does not solve the issue above. Prefer returning a copy of your set.
Make your variables final whenever you can when in a multi-threading environment - it solves many thread safety issues.
Prefer implementing Runnable than extending Thread
You will need to synchronize ALL accesses to your set (read and write), for example by using a synchronizedSet or even better by wrapping a ConcurrentHashMap which generally provides better performance.
instead of peek+poll you can simply take from your queue
So your final class could look like:
public class StreamTask implements Runnable {
private final Set<String> allSymbolSet;
private final PriorityBlockingQueue<String> priorityBlocking = new PriorityBlockingQueue<String>();
public StreamTask() {
String[] symbols = {"USBC", "TCSD", "PCLJ"};
//use a thread safe set, for example based on ConcurrentHashMap
allSymbolSet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean> ());
Collections.addAll(allSymbolSet, symbols);
}
public void addSymbols(String str) {
if (str != null) {
priorityBlocking.add(str);
}
}
public Set<String> getSymbols() {
return new HashSet<> (allSymbolSet); //return a copy
}
public void run() {
while (true) {
try {
allSymbolSet.add(priorityBlocking.take());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Finally, I might be missing something, but that class looks equivalent to the much simpler:
public class StreamTask {
private final Set<String> allSymbolSet;
public StreamTask() {
String[] symbols = {"USBC", "TCSD", "PCLJ"};
//use a thread safe set, for example based on ConcurrentHashMap
allSymbolSet = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean> ());
Collections.addAll(allSymbolSet, symbols);
}
public void addSymbols(String str) {
if (str != null) {
allSymbolSet.add(str);
}
}
public Set<String> getSymbols() {
return new HashSet<> (allSymbolSet); //return a copy
}
}
Better way is method 2. Writing a getter method. If you want to allow set the values then use a setter later. Then your data will be encapsulated .
Write a get Method which is supposed to return the Set. by using this your private remains private and you also access it from outside using Object of the same class.

Java fine-grained synchronization in getter/setter methods and singleton pattern of a class

I'm trying to use the synchronization java directive to implement fine-grained synchronization in a class, i.e. synchronize the least amount of code I can.. I'll comment the code inline, to explain what I do and after the code I'll ask you how to improve the code:
public class MyClass {
private static volatile MyClass singletonInstance = null;
private HashMap<String, Integer> mHashMap = null;
private String mStringA = null;
private String mStringB = null;
// Use double check technique to use synchronization only
// at the first getInstance() invocation
public static MyClass getInstance() {
if (singletonInstance == null) {
synchronized (MyClass.class) {
if (singletonInstance == null)
singletonInstance = new MyClass();
// Initialize class member variables
singletonInstance.mHashMap = new HashMap<String,Integer>();
singletonInstance.mStringA = new String();
singletonInstance.mStringB = new String();
}
}
return singletonInstance;
}
// The following two methods manipulate the HashMap mHashMap
// in a secure way since they lock the mHashMap instance which
// is always the same and is unique
public Integer getIntegerFromHashmap(String key) {
synchronized (mHashMap) {
return mHashMap.get(key);
}
}
public void setIntegerIntoHashmap(String key, Integer value) {
synchronized (mHashMap) {
mHashMap.put(key, value);
}
}
// With the two String members mStringA and mStringB the problem is
// that the instance of String pointed by the member is varied by the
// setter methods, so we can not lock in a fine grained way and we
// must lock on the singletonInstance.
public String getStringA() {
synchronized (singletonInstance) {
return mStringA;
}
}
public String getStringB() {
synchronized (singletonInstance) {
return mStringB;
}
}
public void setStringA(String newString) {
synchronized (singletonInstance) {
mStringA = newString;
}
}
public void setStringB(String newString) {
synchronized (singletonInstance) {
mStringB = newString;
}
}
}
What I don't like about the getter and setter methods of the two String member variables is that locking on singletonInstance can make a thread trying to access mStringB wait until a thread that is manipulating mStringA releases its lock. What will you do in this case? Would you create two member variables like private final Integer mStringALock = new Integer(0) and private final Integer mStringBLock = new Integer(0) in MyClass and use them in the synchronized block of the getter and setter methods of mStringA and mStringB, respectively?
If you have some ideas about how to improve the above code and the proposed variation for fine-grained synchronization of the String member variables, you are welcome :)
Often simpler solutions are easier to implement. I would also use the concurrent library adding in 2004.
This doesn't require explicit locks and each container is thread safe.
You can use AtomicReference but in this case it doesn't give you anything volatile doesn't give you already. (As kdgregory pointed out) You might use AtomicReference in more complex cases.
public enum MyClass {
INSTANCE;
private final Map<String, Integer> mHashMap = new ConcurrentHashMap<String, Integer>();
private volatile String mStringA = null;
private volatile String mStringB = null;
// The following two methods manipulate the HashMap mHashMap
// in a secure way
public Integer getIntegerFromHashmap(String key) {
return mHashMap.get(key);
}
public void setIntegerIntoHashmap(String key, Integer value) {
mHashMap.put(key, value);
}
public String getStringA() {
return mStringA;
}
public String getStringB() {
return mStringB;
}
public void setStringA(String newString) {
mStringA = newString;
}
public void setStringB(String newString) {
mStringB = newString;
}
}
Yes, you need the two separate locks if you want the threads to be able to call the two methods concurrently. I would say there is nothing to improve about this.
However, I noticed that your getInstance() method tries to minimize the size of the block to synchronize but you actually don't achieve that, i.e. you check that the singletonInstance == null inside the synchronized block too. So, i think it would be better to qualify the entire method with synchronized.
It shortens the code of that method and it makes it a little bit more natural too.
Where to begin ...
OK, double-checked locking: it's broken (still), don't use it. If you feel you must use a singleton (and really, they're a bad idea in general, use dependency injection instead), then synchronize the getter method, and return quickly. The likelihood of contested synchronization in this case is very low unless you have a truly enormous number of cores (as in, thousands) and are constantly calling the getter method.
Replace the HashMap with a ConcurrentHashMap. Doug Lea is better at concurrent coding than either you or me.
Mark the string variables as volatile and don't synchronize them.

Categories