How can I apply conditional thread safety upon operation? - java

Consider you have a shared memory (List) which will serve as the "critic section".
Now, consider you that you always have items in the list for these scenarios and you want that your system will behave this way:
Thread1 get some item from the list, in the very same time Thread2 wants to add item to the list. Allow this scenario( in assumption I will take first item from begining and insert the new item in the end of the list - in the SAME TIME!).
Thread1 wants to get an item and in the same time Thread2 wants to get an item too.
This should fail.
THANKS

One possibility is to wrap your List in a class that proxies or overrides the get and add methods.
That way, you can use an explicit Lock on the add method, so that only one thread can add at any given time.
See for instance:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html
You could do this either by extending a List implementation, and overriding the add and get methods (or all relevant methods), or by using composition instead of inheritance, having a proxy class that forwards the calls to the list, but decorates the add and get with the explicit obtaining of the Lock.
A very simple example would be something like:
public class SharedMemory<K> {
private final List<K> memoryList;
private static final ReentrantLock lock = new ReentrantLock();
public SharedMemory() {
memoryList = new ArrayList<>();
}
public void storeItem(K item) {
memoryList.add(item);
}
public K getItem(int pos){
lock.lock();
try{
return memoryList.get(pos);
} finally {
lock.unlock();
}
}
}

Related

Adding or deleting elements concurrently from a Hashmap and achieving synchronization

I am new to Java and concurrency stuff.
The purpose of the assignment was to learn concurrency.
- So when answering this question please keep in mind that I am supposed to use only Hashmap (which is not synchronized by nature) and synchronize it myself. If you provide more knowledge its appreciated but not required.
I declared a hashmap like this:
private HashMap<String, Flight> flights = new HashMap<>();
recordID is the key of the flight to be deleted.
Flight flightObj = flights.get(recordID);
synchronized(flightObj){
Flight deletedFlight = flights.remove(recordID);
editResponse = "Flight with flight ID " + deletedFlight.getFlightID() +" deleted successfully";
return editResponse;
}
Now my doubt: Is it fine to synch on the basis of flightObj?
Doubt 2:
Flight newFlight = new Flight(FlightServerImpl.createFlightID());
flights.put(newFlight.getFlightID(),newFlight);
If I create flightts by using above code and if more than 1 thread try execute this code will there be any data consistency issues ? Why or why not?
Thanks in advance.
To quickly answer you questions:
Both are not okay - you can't remove two different objects in parallel, and you can't add two different objects in parallel.
From java documentation:
If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be "wrapped" using the Collections.synchronizedMap method. This is best done at creation time, to prevent accidental unsynchronized access to the map:
So, it's okay for many threads to use get concurrently and even put that replaces an object.
But if you remove or add a new object - you need to synchronize before calling any hashmap function.
In that case you can either do what's suggested in the documentation and use a global lock. But, it seems that since some limited concurrency is still allowed, you could get that concurrency it by using a read/write lock.
You can do the following
class MySynchronizedHashMap<E> implements Collection<E>, Serializable {
private static final long serialVersionUID = 3053995032091335093L;
final Collection<E> c; // Backing Collection
final Object mutex; // Object on which to synchronize
SynchronizedCollection(Collection<E> c) {
this.c = Objects.requireNonNull(c);
mutex = this;
}
public boolean add(E e) {
synchronized (mutex) {return c.add(e);}
}
public boolean remove(Object o) {
synchronized (mutex) {return c.remove(o);}
}
}
MySynchronizedHashMap mshm = new MySynchronizedHashMap<>(new HashMap<String, Flight>());
mshm.add(new Flight());

Understanding synchronized on listeners notifiers

I have singleton thread class that sometimes calls function below and notifies listeners from it's thread run() method :
public class Serial implements Runnable
{
private ArrayList observers = new ArrayList();
...
public void run()
{
notifyListeners(new CS());
}
public synchronized void notifyListeners(CS value)
{
log.debug("notifying listeners with Control ");
int os = observers.size();
for (int i = 0; i < observers.size(); i++)
{
MListener observer = (MListener) observers.get(i);
observer.dataReceived(value);
}
}
...
public void addListener(MListener lsn)
{
observers.add(lsn);
}
public void removeListener(MListener lsn)
{
observers.remove(lsn);
}
}
I'm just wondering what gives synchronized on notifyListeners method? One of reasons - not allow add/remove observers from/to ArrayList observers while notifyListeners is called. Please correct me if I'm wrong. What more it might give?
UPD
I have updated my code with two methods addListener and removeListener. I suppose it is mistake since both of these methods are not synchronized and might be called from another thread ?
IMO the synchronization on notify does not make sense. If I understand you correctly, the notify method is only called by your singleton thread.
But your observer implementations content probably might be accessed by different threads. There the access to internal state must be synchronized.
E.g. if you want to save the given value to a member of the observer, which later is used by e.g. the main GUI thread you must synchronize the access to this member:
// called by your notify thread
void dataReceived( CS value)
{
synchronized (this)
{
myValue = value;
}
}
and:
// called by your GUI main thread:
public CS getValue()
{
synchronized (this)
{
// optional check for not null:
if ( myValue == null) throw new IllegalStateException();
logger.debug( "returning value: " + myValue);
return myValue;
}
}
If the CS is an AtomicXY (e.g. AtomicInteger) class, the synchronization is not needed. But if you want to do more than just assigning/returning the value (e.g. some checking or log output) the synchronization is mandatory.
The answer mostly depends on your context because it could be for 2 potential reasons:
We want to protect your list of listeners from concurrent accesses and modifications because it is an ArrayList which is not thread-safe (assuming that that the list can be modified elsewhere in your code and any time it is modified it is protected by a synchronized block with this as object's monitor otherwise it would not be done properly and/or it would be useless).
We want to prevent concurrent notifications for some internal logic.
In your case as you only have one thread that calls notifyListeners #2 should not be the reason unless the code owner assumed that you could have several threads doing this task in the future.
The reason #1 makes sense only if the list of observers can be modified by other threads concurrently if it is not possible you can simply remove the keyword synchronized from your method declaration as it would be useless so it would affect the performances for nothing.
Assuming that #1 is the reason, you should rather use the thread-safe List CopyOnWriteArrayList instead of an ArrayList because it is very efficient in mostly read accesses scenarios which is generally the case of a list of observers that we mostly read and rarely modify, your code would then be something like that:
public class Serial implements Runnable {
private final List<MListener> observers = new CopyOnWriteArrayList<>();
...
public void notifyListeners(CS value) {
log.debug("notifying listeners with Control ");
for (MListener observer : observers) {
observer.dataReceived(value);
}
}
I suppose it is mistake since both of these methods are not
synchronized and might be called from another thread ?
I confirm that the current code is not correct since your list of observers can be modified by concurrent threads thanks to the public methods addListener and removeListener and those methods don't modify your list within a synchronized block with this as object's monitor such that the current code is not thread-safe as it doesn't prevent concurrent accesses to your non thread-safe list.

How do I synchronize access to a member of a different class?

I'm trying to figure out how to synchronize read/write access to a synchronized list from a different class.
A small example: I have a synchronized list in one class ListProvider and I access it in a different class Filter. As the name suggests, this class performs some filtering based on a (in)validation check isInvalid.
The filter method first gets the list reference, then collects the entries to remove in a temporary list to not run into concurrent modification issues, and finally removes the entries from the list:
public class Filter {
ListProvider listProvider;
...
public void filter() {
List<String> listProviderList = listProvider.getList();
List<String> entriesToRemove = new ArrayList<>();
// collect
for (String entry : listProviderList)
if (isInvalid(entry)) {
entriesToRemove.add(entry);
}
}
// remove
for (String entry : entriesToRemove) {
listProviderList.remove(entry);
}
}
}
My question: How can I make sure that no other thread modifies the list while filter does its reading and writing?
If it were Filter's own list, I'd just do:
synchronized(myList) {
// collect
// remove
}
but in this case I'm not sure what to use as a monitor.
but in this case I'm not sure what to use as a monitor.
To create a monitor for a specific task, it is a good pattern to use a private final Object:
private final Object listUpdateLock = new Object();
...
synchronized(listUpdateLock) {
...
}
It's important to make sure that ListProvider is private and that all accesses to the list are done within a synchronized block -- even if only reading from it.
In this case, you are updating the list, you could create a temporary list and then replace it when you are done. I'm not sure you can do that with ListProvider however. Then you could just make the list volatile.
Here it seems like you should use a lock. A lock is like synchronized but it's a bit more flexible. It doesn't require a surrounding block and it has some extended features. There are also some different kinds of locks. ReentrantLock is much like synchronized.
public class ListProvider<E> {
private final List<E> theList = new ArrayList<E>();
private final ReentrantLock listLock = new ReentrantLock();
public final List<E> lockList() {
listLock.lock();
return theList;
}
public final void unlockList() {
listLock.unlock();
}
}
/* somewhere else */ {
List<E> theList = listProvider.lockList();
/*
* perform
* multiple
* operations
*
*/
listProvider.unlockList();
}
The main differences between this and synchronized are:
The actual locking mechanism is hidden. This is good for abstraction; however,
Clients must remember to unlock explicitly whereas a synchronized monitor exit is at a block delimiter.
There is a lock called ReentrantReadWriteLock which you might find useful because multiple threads can read simultaneously. ReadWriteLock explains how it works.
Do not iterate over original list, but create a copy of it to find invalid elements. When you are done with filtering you can remove invalid elements from original list safely:
public class Filter {
ListProvider listProvider;
...
public void filter() {
List<String> listProviderCopy = new ArrayList<>(listProvider.getList());
List<String> entriesToRemove = new ArrayList<>();
// collect
for (String entry : listProviderCopy)
if (isInvalid(entry)) {
entriesToRemove.add(entry);
}
}
listProvider.getList().removeAll(entriesToRemove);
}
}
You may want to use SynchronizedList
List<String> list = new ArrayList<>();
List<String> synch = Collections.synchronizedList(list);
more

List ConcurrentModificationException in servlet

It's plenty of questions regarding ConcurrentModificationException for ArrayList objects, but I could not find yet an answer to my problem.
In my servlet I have an ArrayList as a member object:
List myList<Object> = new ArrayList<Object> (...);
The list must be shared among users and sessions.
In one of the servlet's methods, method1, I need to iterate over the ArrayList items, and eventually add clear the list after the iteration. Here a snippet:
for (Object o : myList) {
// read item o
}
myList.clear();
In another method, method2, I simply add a new Item to the list.
Most of the times the method ends its job without errors. Sometimes, probably due to the concurrent invocation of this method by different users, I get the famous java util.ConcurrentModificationException exception.
Should I define my List as:
List myList = Collections.synchronizedList(new ArrayList(...));
Would this be enough or am I missing something? What's behind the scenes? When there is a possible concurrency, is the second thread held in standby by the container?
EDIT: I have added the answers to some comments.
Using a synchronized list will not solve your problem. The core of the problem is that you are iterating over a list and modifying it at the same time. You need to use mutual exclusion mechanisms (synchronized blocks, locks etc) to ensure that they do not happen at the same time. To elaborate, if you start with:
methodA() {
iterate over list {
}
edit list;
}
methodB() {
edit list;
}
If you use a synchronized list, what you essentially get is:
methodA() {
iterate over list {
}
synchronized {
edit list;
}
}
methodB() {
synchronized {
edit list;
}
}
but what you actually want is:
methodA() {
synchronized {
iterate over list {
}
edit list;
}
}
methodB() {
synchronized {
edit list;
}
}
Just using synchronizedList makes all methods thread safe EXCEPT Iterators.
I would use CopyOnWriteArrayList. It is thread safe and doesn't produce ConcurrentModificationException.
ConcurrentModificaitonException occurs when you attempt to modify a collection while you're iterating through it. I imagine that the error only gets thrown when you perform some conditional operation.
I'd suggest pushing the values you want to add/remove into a separate list and performing the add /remove after you're done iterating.
You need to lock not just over the method accesses but over your use of the list.
So if you allocate a paired Object like:
Object myList_LOCK = new Object();
then you can lock that object whenever you are accessing the List, like this:
synchronized(myList_LOCK) {
//Iterate through list AND modify all within the same lock
}
at the moment the only locking you're doing is within the individual methods of the List, which isn't enough in your case because you need atomicity over the entire sequence of iteration and modification.
You could use the actual object (myList) to lock rather than a paired object but in my experience you are better off using another dedicated object as it avoids unexpected deadlock conditions that can arise as a result of the code internal to the object locking on the object itself.
This is kind of an add onto Peter Lawery's answer. But since copying wouldn't effect you too negatively you can do a mixture of copying with synchronization.
private final List<Object> myList = new ArrayList<Object>();
public void iterateAndClear(){
List<Object> local = null;
synchronized(myList){
local = new ArrayList<Object>(myList);
myList.clear();
}
for(Object o : local){
//read o
}
}
public void add(Object o){
synchronized(myList){
myList.add(o);
}
}
Here you can iterate over o elements without fear of comodifications (and outside of any type of synchronization), all while myList is safely cleared and added to.

Why does this code throw a java ConcurrentModificationException?

public final class ClientGateway {
private static ClientGateway instance;
private static List<NetworkClientListener> listeners = Collections.synchronizedList(new ArrayList<NetworkClientListener>());
private static final Object listenersMutex = new Object();
protected EventHandler eventHandler;
private ClientGateway() {
eventHandler = new EventHandler();
}
public static synchronized ClientGateway getInstance() {
if (instance == null)
instance = new ClientGateway();
return instance;
}
public void addNetworkListener(NetworkClientListener listener) {
synchronized (listenersMutex) {
listeners.add(listener);
}
}
class EventHandler {
public void onLogin(final boolean isAdviceGiver) {
new Thread() {
public void run() {
synchronized (listenersMutex) {
for (NetworkClientListener nl : listeners)
nl.onLogin(isAdviceGiver);
}
}
}.start();
}
}
}
This code throws a ConcurrentModificationException
But I thought if they are both synchronized on the listenersMutex then they should be executed in serial? All code within functions that operate on the listeners list operate within syncrhonized blocks that are synchronized on the Mutex. The only code that modifies the list are addNetworkListener(...) and removeNetworkListener(...) but removeNetworkListener is never called at the moment.
What appears to be happening with the error is that a NetworkClientListener is still being added while the onLogin function/thread is iterating the listeners.
Thank you for your insight!
EDIT: NetworkClientListener is an interface and leaves the implementation of "onLogin" up to the coder implementing the function, but their implementation of the function does not have access to the listeners List.
Also, I just completely rechecked and there is no modification of the list outside of the addNetworkListener() and removeNetworkListener() functions, the other functions only iterate the list. Changing the code from:
for (NetworkClientListener nl : listeners)
nl.onLogin(isAdviceGiver);
To:
for(int i = 0; i < listeners.size(); i++)
nl.onLogin(isAdviceGiver);
Appears to solve the concurrency issue, but I already knew this and would like to know what's causing it in the first place.
Thanks again for your continuing help!
Exception:
Exception in thread "Thread-5" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:782)
at java.util.ArrayList$Itr.next(ArrayList.java:754)
at chapchat.client.networkcommunication.ClientGateway$EventHandler$5.run(ClientGateway.java:283)
EDIT Okay, I feel a little dumb. But thank you for all your help! Particularly MJB & jprete!
Answer: Someone's implementation of onLogin() added a new listener to the gateway. Therefore(since java's synchronization is based on Threads and is reentrant, so that a Thread may not lock on itself) when onLogin() was called we in his implementation, we were iterating through the listeners and in the middle of doing so, adding a new listener.
Solution: MJB's suggestion to use CopyOnWriteArrayList instead of synchronized lists
Mutexes only guard from access from multiple threads. If nl.onLogin() happens to have logic that adds a listener to the listeners list, then a ConcurrentModificationException may be thrown, because it's being accessed (by the iterator) and changed (by the add) simultaneously.
EDIT: Some more information would probably help. As I recall, Java collections check for concurrent modifications by keeping a modification count for each collection. Every time you do an operation that changes the collection, the count gets incremented. In order to check the integrity of operations, the count is checked at the beginning and end of the operation; if the count changed, then the collection throws a ConcurrentModificationException at the point of access, not at the point of modification. For iterators, it checks the counter after every call to next(), so on the next iteration of the loop through listeners, you should see the exception.
I must admit that I don't see it either - if indeed removeListeners is not called.
What is the logic of the nl.onLogin bit? If it modified stuff, it could cause the exception.
A tip btw if you expect listeners to be moderately rare in being added, you could make the list CopyOnWriteArrayList type -- in which case you don't need your mutexes at all - CopyOnWriteArrayList is totally thread safe, and returns a weakly consistent iterator that will never throw CME (except where I just said, in nl.onLogin).
Instead of ArrayList , use can use thread-safe class CopyOnWriteArrayList which does not throw ConcurrentModificationException even if it is modified while iterating. While iterating if it is attempted to modify(add,update) then it makes a copy of the list, but iterater will continue working on original one.
Its a bit slower than ArrayList . It is useful in cases where you do not want to syncronise the iterations.

Categories

Resources