Use CAS instead of synchronized - java

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.

Related

Java synchronization depending on method parameter

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);
}
}
}
}

HashMap manipulated on 2 different methods - multi-threading and cuncurrency

I've got the following code pieces , containing 2 different methods that both methods will be accessed by many threads (getWeapon() and returnWeapon()).
Please anyone who can answer some or all of the following questions:
1. How can I make it as efficient as possible?
2. Can I not use the synchronized block?
3. Is it better to use a different Object as the key to the synchronizd block?
4. Is it better to use ReentrantLock/ReadWriteLock to handle this cuncurrent multi-threading cases?
private static final int M16_NUM_WEAPONS = 2;
private static final int AK47_NUM_WEAPONS = 5;
private static final int UZI_NUM_WEAPONS = 9;
private Map<Class<? extends Weapon>, Integer> WeaponsToAmountMap;
public Arsenal() {
this.synchronizedWeaponsToAmountMap = new ConcurrentHashMap<Class<? extends Weapon>, Integer>();
}
public void initializeWeapons() {
synchronizedWeaponsToAmountMap.put(M16.class, M16_NUM_WEAPONS);
synchronizedWeaponsToAmountMap.put(AK47.class, AK47_NUM_WEAPONS);
synchronizedWeaponsToAmountMap.put(Uzi.class, UZI_NUM_WEAPONS);
}
public Weapon getWeapon(Fighter fighter) {
List<Class<? extends Weapon>> allowedWeapons = new ArrayList<>(fighter.getAllowedWeapons());
Class<? extends Weapon> weaponClass = null;
for (Class<? extends Weapon> allowedWeapon : allowedWeapons){
synchronized (this) {
Integer amount = synchronizedWeaponsToAmountMap.get(allowedWeapon);
if (amount != null && amount > 0) {
synchronizedWeaponsToAmountMap.put(allowedWeapon, amount - 1);
System.out.println("Taking : "+allowedWeapon.getSimpleName());
weaponClass = allowedWeapon;
break;
}
}
}
if (weaponClass==null){
return null;
}
Weapon weapon = null;
try {
weapon = weaponClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return weapon;
}
public void returnWeapon(Weapon weapon) {
if (weapon==null){
return;
}
synchronized(this) {
System.out.println("returning : "+weapon.getClass().getSimpleName());
synchronizedWeaponsToAmountMap.put(weapon.getClass(), synchronizedWeaponsToAmountMap.get(weapon.getClass()) + 1);
}
}
I think it doesn't matter much different whether your synchronization done on one or different monitor objects: as soon as you want to prevent different threads access the same shared data simultaneously you use synchronization and it's linearize the access and then increase the time.
The java.util.concurrent functionality generally and Reentrant/ReadWriteLock particularly use non-blocking approach and then might be faster -- but would be or not completely depends on how your threads interact with shared data...

Consumer-Producer with high contention

I would like to know what would be the best mechanism to implement multiple Producer - single Consumer scenario, where i have to keep the current number of unprocessed requests up to date.
My first thought was to use ConcurrentLinkedQueue:
public class SomeQueueAbstraction {
private Queue<SomeObject> concurrentQueue = new ConcurrentLinkedQueue<>();
private int size;
public void add(Object request) {
SomeObject object = convertIncomingRequest(request);
concurrentQueue.add(object);
size++;
}
public SomeObject getHead() {
SomeObject object = concurrentQueue.poll();
size--;
}
// other methods
Problem with this is that i have to explicitly synchronize on add and size ++, as well as on the poll and size--, to have always accurate size which makes ConccurentLinkedQueue pointless to begin with.
What would be the best way to achieve as good as possible performance while maintaining data consistency ?
Should I use ArrayDequeue instead and explicitly synchronize or there is a better way to achieve this ?
There is sort of similar question/answer here:
java.util.ConcurrentLinkedQueue
where it is discussed how composite operations on ConcurrentLinkedQueue are naturally not atomic but there is no direct answer what is the best option for the given scenario.
Note: I am calculating size explicitly because time complexity for inherent .size() method is O(n).
Note2: I am also worried that getSize() method, which i haven't explicitly written, will add to even more contention overhead. It could be called relatively frequently.
I am looking for the most efficient way to handle Multiple Producers - single Consumer with frequent getSize() calls.
Alternative suggestion: If there was elementId in SomeObject structure, i could get current size from ConcurrentLinkedQueue.poll() and only locking would have to be done within mechanism to generate such id. Add and get could now properly be used without additional locking. How would this fare as an alternative ?
So the requirement is to report an up to date current number of unprocessed requests. And this is requested often which indeed makes ConcurrentLinkedQueue.size() unsuitable.
This can be done using an AtomicInteger: it is fast and is always as close to the current number of unprocessed requests as possible.
Here is an example, note some small updates to ensure that the reported size is accurate:
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class SomeQueueAbstraction {
private final Queue<SomeObject> concurrentQueue = new ConcurrentLinkedQueue<>();
private final AtomicInteger size = new AtomicInteger();
public boolean add(Object request) {
SomeObject object = convertIncomingRequest(request);
if (concurrentQueue.add(object)) {
size.incrementAndGet();
return true;
}
return false;
}
public SomeObject remove() {
SomeObject object = concurrentQueue.poll();
if (object != null) {
size.decrementAndGet();
}
return object;
}
public int getSize() { return size.get(); }
private SomeObject convertIncomingRequest(Object request) {
return new SomeObject(getSize());
}
class SomeObject {
int id;
SomeObject(int id) { this.id = id; }
}
}
You can use an explicit lock, which means you probably won't need a concurrent queue.
public class SomeQueueAbstraction {
private Queue<SomeObject> queue = new LinkedList<>();
private volatile int size;
private Object lock = new Object();
public void add(Object request) {
SomeObject object = convertIncomingRequest(request);
synchronized(lock) {
queue.add(object);
size++;
}
}
public SomeObject getHead() {
SomeObject object = null;
synchronized(lock) {
object = queue.poll();
size--;
}
return object;
}
public int getSize() {
synchronized(lock) {
return size;
}
}
// other methods
}
This way, adding/removing elements to/from the queue and updating the size will be done safely.

Can overriding be an effective replacement for an if statement in lazy initialization and in general?

I'm trying to mimic the following abstract class, designed to enable only one lazy initialization, without using logic statements. I'm ignoring the synchronization elements necessary for thread safety for simplicity's sake.
abstract class Thunk<T>
{
private boolean initiated = false;
private T value;
public T get()
{
if(!initiated) // not using (value == null)
{
value = compute();
initiated = true;
}
return value;
}
abstract protected T compute();
}
Can an instance of the following abstract class be hacked by a child to initialize the same variable more than once?
abstract class Thunk<T>
{
private T value;
private Computer<T> computer;
public Thunk()
{
computer = new Computer<T>(this);
}
public T get()
{
value = computer.getValue();
return value;
}
abstract protected T compute();
private class Computer<T>
{
private static final String TAG = "Computer";
private Thunk<T> thunk;
private T value;
private Computer<T> computer;
public Computer(Thunk<T> thunk)
{
Log.d(TAG, "constructed");
this.thunk = thunk;
computer = this;
}
public T getValue()
{
Log.d(TAG + ".getValue()", "");
value = computer.computeValue();
return value;
}
protected T computeValue()
{
Log.d(TAG + ".computeValue()", "");
value = thunk.compute();
computer = new DumbComputer<T>(thunk, value);
return value;
}
//this is for maximal encapsulation
private class DumbComputer<T> extends Computer<T>
{
private static final String TAG = "DumbComputer";
private T value;
public DumbComputer(Thunk<T> thunk, T value)
{
super(thunk);
Log.d(TAG + ".contructed()", "booki");
this.value = value;
}
//overriding so that value will be calculated only once.
#Override
protected T computeValue()
{
Log.d(TAG + ".computeValue()", "");
return value;
}
}
}
}
Yes, by overriding the get method.
To fix that you can make the get into a final method. That will prevent overriding and give you singleton-like behaviour.
Note that the code you have written is not thread safe.
You could achieve thread safety by making the method synchronized (don't worry about performance until you know you gave a problem and that the method is the hotspot, because slow correct code is better than fast incorrect code, and the JVM is very good at optimising locks. If you find a specific lock for this class to be excessively hot, you can use a number of tricks to speed it up... but don't worry about that just yet)
Also worth pointing out the resource holder inner class pattern for lazy init (not applicable to your use case as this class need. It be used for only singletons) can be used if you wan the best lazy init of singletons.
update (responding to comment as comments don't support formatting)
Do this:
abstract class Thunk<T>
{
private boolean initiated = false;
private T value;
public synchronized final T get()
{
if(!initiated) // not using (value == null)
{
value = compute();
initiated = true;
}
return value;
}
abstract protected T compute();
}
That is the simplest code that can possibly work. Don't even dream of trying to "improve" that code. It can be improved, but the improvements will differ depending on how the class is being used, and the complexity of the improvement will hide what your code is trying to do. Start with the simplest thing that can work, and go from there.
Keep It Simple Stupid
And don't solve problems you don't have yet
The pattern
public final void f() {
...
X x = ...;
g(x);
...
}
abstract protected void g(X x);
is quite usefull in contractual programming:
to impose a behaviour (body of f), and
to provide a local context (x).
A behaviour often is realized by holding a state (like your initiated).
So yes, it is fine for lazy evaluation. Though lazy evaluation can be achieved on field level, for instance by the seldom seen jewel Future<>.
Your second example does not work as (probably) intended, as you create a new DumbComputer each time you call Thunk.get. You can achieve your goal as follows (but I do not think it's good design, and I really do not see where the advantage compared to an easier solution shuld be):
abstract class Thunk<T> {
T value;
Computer<T> computer;
protected abstract T doCompute ();
private interface Computer<T> {
Computer getComputer ();
T compute ();
}
public Thunk<T> () {
// initialize computer with a calculating one
computer = new Computer<T> () {
Computer getComputer () {
// return a dumb computer
return new Computer<T> () {
Computer getComputer () { return this; }
T compute () { return value; }
}
}
T compute () { value = doCompute (); return value; }
};
}
public T getValue () {
T v = computer.compute (); computer = computer.getComputer (); return v;
}
}

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