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

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.

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

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.

List variable assigned through Thread Constructor by reference is not working

I am initializing class variable of one of my Thread via its constructor through one
of my service class as below:
ProcessMediaThread pThread = new ProcessMediaThread(listMediaPath, mediaType);
pThread.start();
where listMediaPath is an ArrayList<String>(); object.
Inside ProcessMediaThread class:
public class ProcessMediaThread extends Thread
{
private List<String> absoluteMediaPath= new ArrayList<String>();
private String mediaType;
public ProcessMediaThread(List<String> absoluteMediaPathList, String mediaType)
{
this.absoluteMediaPath = absoluteMediaPathList;
this.mediaType= mediaType;
}
My overridden run() method:
#Override
public void run()
{
if(mediaType.equals(MediaType.PHOTO)) //<- mediaType value is retained..
{
for(int i=0;i<absoluteMediaPath.size();i++) // <- here absoluteMediaPath is empty..!!
{
//...
}
One of my friend suggest me to follow different approach at constructor level:
this.absoluteMediaPath.addAll(absoluteMediaPathList);
which worked..!!
Can anyone suggest where exactly the problem is arising and what does addAll(Collection<? extends E> c); is doing ?
If you use addAll, you're copying the contents of the list into a separate collection within ProcessMediaThread. That means changes to it from outside won't affect it. For example, consider:
ProcessMediaThread pThread = new ProcessMediaThread(listMediaPath, mediaType);
pThread.start();
listMediaPath.clear();
With your current code, your new thread may see an empty collection - or it may see a collection which has data and then is suddenly cleared. It's not a good situation to be in. Additionally, ArrayList isn't thread-safe, so modifying it in one thread and reading it in another could well cause problems.
When you create a private copy (using addAll), the clear() on the third line above will have no effect, as it's not affecting the same collection that the thread is using.
A few other points:
I would suggest that you implement Runnable separately rather than extending Thread. You can then pass an instance of your Runnable to a Thread constructor; this gives a better separation of "mechanics to run a task on a new thread" and "the task to be run".
Unless you actually need the value of i in your loop, you can just use:
for (String mediaPath : absoluteMediaPath) {
...
}
An alternative to calling addAll would be to only initialize your collection in the constructor, using the ArrayList(Collection) constructor.
So with all of these together, I'd change your class to something like:
public class MediaProcessor implements Runnable {
private final List<String> absoluteMediaPath;
private final String mediaType;
public MediaProcessor(List<String> absoluteMediaPathList, String mediaType) {
this.absoluteMediaPath = new ArrayList(absoluteMediaPathList);
this.mediaType = mediaType;
}
#Override
public void run() {
if (mediaType.equals(MediaType.PHOTO)) {
for (String mediaPath : absoluteMediaPath) {
...
}
}
}
}
...
Thread thread = new Thread(new MediaProcessor(listMediaPath, mediaType));
thread.start();

ThreadLocal<T> Documentation in JDK

JDK 1.6 documentation shows an example about how to use LocalThread<T>. I copy and paste it here:
For example, the class below generates unique identifiers local to each thread. A thread's id is assigned the first time it invokes UniqueThreadIdGenerator.getCurrentThreadId() and remains unchanged on subsequent calls.
import java.util.concurrent.atomic.AtomicInteger;
public class UniqueThreadIdGenerator {
private static final AtomicInteger uniqueId = new AtomicInteger(0);
private static final ThreadLocal <Integer> uniqueNum =
new ThreadLocal <Integer> () {
#Override
protected Integer initialValue() {
return uniqueId.getAndIncrement();
}
};
public static int getCurrentThreadId() {
return uniqueId.get();
}
} // UniqueThreadIdGenerator
My problem is:
when multiple threads call UniqueThreadIdGenerator.getCurrentThreadId() it only returns 0 because there is no initialization. Shouldn't it be like this:
public static int getCurrentThreadId() {
return uniqueNum.get();
}
Now after the first call, it goes and initialize the variable.
Yes, it should be uniqueNum.get(). The JDK 7 docs get it right, and use better names:
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadId {
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId =
new ThreadLocal<Integer>() {
#Override protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
return threadId.get();
}
}
It's not really a matter of initialization though - it's simply a matter of using the wrong member entirely. Even if lots of code had used uniqueNum in the original code, getCurrentThreadId() would always have returned "the next ID to be assigned" instead of "the ID assigned for the current thread".

Categories