I'm having some issues with a piece of java code which keeps triggering a ConcurrentModificationException. I can't really figure out what is going on, this is a fairly simple static class, not sure why it would be throwing this exception as everything is synchronized. This piece of code has been heavily used for several years, so it's odd that it would start having issues at this point:
java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:953)
at java.util.LinkedList$ListItr.next(LinkedList.java:886)
at DataSubscriptionManager.sendMessages(DataSubscriptionManager.java:18)
private static HashMap<DataClass,LinkedList<DataSubscriber>> subscriberMap = new HashMap();
public static void sendMessages(LinkedList messages, DataClass dataClass) {
synchronized (subscriberMap) {
LinkedList<DataSubscriber> subscribers = subscriberMap.get(dataClass);
if (subscribers != null) {
for (DataSubscriber sub: subscribers) { *** EXCEPTION HAPPENS HERE***
if (sub != null) {
sub.sendMessages(messages);
}
}
}
}
}
public static void addDataSubscriber(DataSubscriber sub, DataClass dataClass) {
synchronized (subscriberMap) {
LinkedList<DataSubscriber> subscribers = subscriberMap.get(dataClass);
if (subscribers == null) {
subscribers = new LinkedList();
subscriberMap.put(dataClass,subscribers);
}
while (subscribers.remove(sub)) {}
subscribers.add(sub);
}
}
public static void removeDataSubscriber(DataSubscriber sub, DataClass dataClass) {
synchronized (subscriberMap) {
LinkedList<DataSubscriber> subscribers = subscriberMap.get(dataClass);
subscribers.remove(sub);
}
}
What's happening is that your collection is being modified while you are iterating over it.
It's could be another thread, or it's possible one of your subscribers is either unsubscribing, or subscribing to a different dataClass in response to the message it receives.
You can try using Collections.synchronizedList(subscribers) which may help avoiding this problem.
Related
I've written a Java class and someone has reviewed the code and insisted that there could be a race condition in method calculate. Here's a simplified version of the class code:
public class MyClass {
private List<Integer> list;
private final ReadWriteLock lock;
public MyClass() {
list = new ArrayList<>();
lock = new ReentrantReadWriteLock();
}
public void add(Integer integer) {
lock.writeLock().lock();
try {
list.add(integer);
} finally {
lock.writeLock().unlock();
}
}
public void deleteAll() {
lock.writeLock().lock();
try {
list.clear();
} finally {
lock.writeLock().unlock();
}
}
public Integer calculate() {
List<Integer> newList = new ArrayList<>();
Integer result = 0;
lock.readLock().lock();
try {
list.forEach(integer -> {
// calculation logic that reads values from 'list' and adds only a subset of elements from 'list' in 'newList'
});
} finally {
lock.readLock().unlock();
}
setList(newList);
return result;
}
private void setList(List<Integer> newList) {
lock.writeLock().lock();
try {
list = newList;
} finally {
lock.writeLock().unlock();
}
}
}
Now my question is:
Can a race condition really happen in this method, and if so how can I solve it (either using locks or using any other method to make the class thread safe)?
Any advice would be appreciated.
There is a time gap between creation of newList and call to setList(newList). We may assume this time gap is arbitrary long, and everything can happen when it lasts, e.g. another thread adds an object which must be retained, but it will be lost when call to setList(newList) removes list with that new object.
In fact, the method calculate is modifying and should do all the work under write lock.
To clarify the above ... the statement
List<Integer> newList = new ArrayList<>();
... instantiates a data-structure (list ...) that will subsequently be used within the block of code that is intended to be protected by lock.readLock().lock();, but is not contained within it. Therefore it is not protected.
To remedy the problem, the declaration of newList should not include initialization. Nothing which affects the presumed value of this variable should exist outside of the lock-protected block.
Can I synchronize method by parameter?
For example - I get person to some method and I want to do some operation for person, but if few thread call this method for the same person I want to do it one by one.
private void dosomething(Long id, Person person) {
dosomethingelse(id, person);
}
How to call dosomethingelse (id, person) only for the same id one by one? but I want that this code for different id-s can be called multithreadly
I wrote this code, but maybe something wrong here or something can be better.
public static class LatchByValue <T> {
public void latch(T value, ConsumerWithException<T> consummer) throws Exception {
CountDownLatch latch = new CountDownLatch(1);
try {
CountDownLatch previousLatch = null;
// we are checking if another thread is already calling this method with the same id
// if sync has CountDownLatch so another thread is already calling this method
// or we put our latch and go on
while ((previousLatch = sync.putIfAbsent(value, latch)) != null) {
try {
// we are waiting for another thread, we are waiting for all threads that put their latch before our thread
previousLatch.await();
} catch (InterruptedException e) {
return;
}
}
consummer.accept(value);
} finally {
latch.countDown();
sync.remove(value, latch);
}
}
private ConcurrentHashMap<T, CountDownLatch> sync = new ConcurrentHashMap<>();
}
Example:
LatchByValue<Long> latch = new LatchByValue<>();
private void dosomething(Long id, Person person) {
latch.latch(
id,
currentId -> { dosomethingelse(currentId, person); }
);
}
Problem with using a CountdownLatch is that you can't "increment" the count so you need to replace the existing latch when it's been used, which complicates the code.
You could instead use a Semaphore with one permit which would allow you to do the same thing but in a simpler way.
Semaphore s = sync.computeIfAbsent(value, x -> new Semaphore(1, true));
s.acquire(); //this blocks and throws InterruptedException, which you need to handle
try {
consummer.accept(value);
} finally {
s.release();
}
You can use synchronized keyword on the parameter passed (culprit: it cannot be null!). And that also allows you to stop worrying about re-acquiring the lock (it's reentrant).
So the implementation would look like:
private void doSomething(Long id, Person person) {
synchronized (person) {
// do something
}
}
Remember that any other accesses (not in doSomething call) also would need to have the synchronization block, e.g.:
// another method, unrelated, but does something with 'person'
private void doSomethingElse(Person person, ... /* other arguments */) {
synchronized (person) {
// do something
}
}
It would be good document (in Person's javadoc) that the user needs to acquire the lock for that object.
If you want to provide a critical section for <id, person> tuple, you'd need to change your API a bit - and then pass that object around in your application.
private void doSomething(IdAndPerson idAndPerson) {
synchronized (idAndPerson) {
// do something
}
}
class IdAndPerson {
private final Long id;
private final Person person;
// constructor etc.
}
private static final Set<Long> lockedIds = new HashSet<>();
private void lock(Long id) throws InterruptedException {
synchronized (lockedIds) {
while (!lockedIds.add(id)) {
lockedIds.wait();
}
}
}
private void unlock(Long id) {
synchronized (lockedIds) {
lockedIds.remove(id);
lockedIds.notifyAll();
}
}
public void doSomething(Long id) throws InterruptedException {
try {
lock(id);
//Put your code here.
//For different ids it is executed in parallel.
//For equal ids it is executed synchronously.
} finally {
unlock(id);
}
}
id can be not only an 'Long' 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.
I cannot decide how to implement this task correctly using RxJava2.
The problem is following. I am recording audio using AuidoRecord.
Currently I have implemented the custom Flowable class like that
private class StreamAudioRecordRunnable extends Flowable<short[]> implements Runnable {
private int mShortBufferSize;
private List<Subscriber<? super short[]>> mSubscribers = new ArrayList<>();
private short[] mAudioShortBuffer;
private void removeAllNullableSubscribers() {
mSubscribers.removeAll(Collections.singleton(null));
}
private void notifyAllSubscribers(short[] audioBuffer) {
removeAllNullableSubscribers();
for (Subscriber<? super short[]> subscriber : mSubscribers) {
subscriber.onNext(audioBuffer);
}
}
#Override
protected void subscribeActual(Subscriber<? super short[]> newSubscriber) {
mSubscribers.add(newSubscriber);
}
private void notifyAllSubscribersAboutError(Throwable error) {
for (Subscriber<? super short[]> subscriber : mSubscribers) {
subscriber.onError(error);
}
}
#Override
public void run() {
// Init stuff
while (mIsRecording.get()) {
int ret;
ret = mAudioRecord.read(mAudioShortBuffer, 0, mShortBufferSize);
notifyAllSubscribers(mAudioShortBuffer);
}
mAudioRecord.release();
}
}
As you can see I am manually adding subscribers to the list. Then when I get new buffer all subscribers are notified.
I am guessing that this is not the most performant way to do this.
What I need
As far as this flowable running in a service. It should run until the service is alive, even if there are no subscribers.
Subscribers are not constant, they may subscribe and then unsubscribe, but the Flowable/Observable should still be running.
As the data emitted by the Flowable is the stream, subscribers should not be notified about already emitted items, they should only get current streaming data. Fire and forget.
The Flowable should run even all subscribers are gone.
Please suggest the right strategy to implement this.
I would be grateful for any help.
Something like
public class StreamAudioRecordRunnable {
private int mShortBufferSize;
private short[] mAudioShortBuffer;
private ConnectedFlowable<short[]> audioFlowable();
public StreamAudioRecordRunnable() {
audioFlowable = Flowable.create(new ObservableOnSubscribe<short[]>() {
#Override
public void subscribe(FlowableEmitter<short[]> emitter) throws Exception {
try {
while (mIsRecording.get()) {
int ret;
ret = mAudioRecord.read(mAudioShortBuffer, 0, mShortBufferSize);
emitter.onNext(mAudioShortBuffer);
}
emitter.onComplete();
mAudioRecord.release();
} catch (Exception e) {
emitter.onError(e);
mAudioRecord.release();
}
}
}).subscribeOn(Schedulers.io()).publish();
}
public Flowable<short[]> getFlowable() {
return audioFlowable.hide();
}
#Override
public void start() {
audioObservable.connect();
}
}
would be my preference.
I'm trying to debug performance issues in multithreaded code and I'm wondering if there's a way to print out the number of threads currently executing the method. For example, suppose I have the following:
public void concurrentMethod(Object data) {
int numberOfThreadsExecutingThisMethodSimulataneously = //...?
System.out.println(numberOfThreadsExecutingThisMethodSimulataneously);
//method body...
}
Specifically, I am using a ThreadPoolExecutor, so jobs are being submitted as follows:
ExecutorService executor;
for (Object data : myData) {
executor.execute(() -> concurrentMethod(data));
}
How about
static AtomicInteger currentNumberOfThreads = new AtomicInteger();
public void concurrentMethod(Object data) {
currentNumberOfThreads.incrementAndGet();
try {
// currentNumberOfThreads.gets()
} finally {
currentNumberOfThreads.decrementAndGet();
}
}
I am looking at some code that is causing an issue (Deadlock) in Java 6 and above, but not in Java 1.5.
BMP Bean:
private MyClass m_c;
public String ejbCreate(String id) throws CreateException, MyException
{
try
{
m_c = Singleton.getInstance().getObj(id);
}
catch (MyException e)
{
synchronized (Singleton.getInstance())
{
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
}
else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
Singleton:
private Map objCache = new HashMap();
private static Singleton INSTANCE = new Singleton();
public static Singleton getInstance() {
return INSTANCE;
}
public void addObj(String id, MyClass o)
{
if (this.objCache.containsKey(id)) {
this.objCache.remove(id);
}
this.objCache.put(id, o);
}
public MyClass getObj(String id) throws Exception
{
MyClass o = null;
o = (MyClass)this.objCache.get(id);
if (o == null) {
throw new MyException("Obj " +id+ " not found in cache");
}
return o;
}
public boolean hasObj(String id)
{
return this.objCache.containsKey(id);
}
The empirical evidence so far shows that putting synchronization round the whole try/catch resolves the deadlock when using Java 6.
Clearly there can be one or more threads calling
Singleton.getInstance().getObj(id)
without obtaining the lock whilst another thread has the lock and is executing the code in the synchronized block, but even after considering memory synchronization detailed in JSR-133, it doesn't look like there should be any issues in this scenario.
I am aware that I haven't explained what the issue is apart from saying it is a deadlock and that it is not ideal to paint only a prat of the picture but to paint the whole picture would take a very big canvas.
I have looked at the notes for Java 6 release and the only area that sounds relevant is around uncontended synchronization, but I do not know if that is significant in this case.
Thank you for any help.
I suspect you are not getting a deadlock (holding two locks in two different threads obtained in a different order), but rather going into an infinite loop. This can happen with HashMap if you are accessing it in a manner which is not thread safe. What happens in the linked list used to handle collisions appears to go back on itself and the reader runs forever. This has always been an issue, though some subtle difference in Java 6 could show up this problem when a different version might not.
I suggest you fix this class so it uses a thread safe collection and not retry on Exception because there is not guarantee this will happen.
There is a lot you could do to improve this class but what you really need is ConcurrentMap.computeIfAbsent added in Java 8.
Note: there is no reason to
check a key exists before attempting to remove it.
remove a key just before attempting to put it.
throw an Exception instead of returning null.
returning null when you can pass it a factory. (as per computeIfAbsent)
use a factory when the type is known in advance.
I suggest you
use a ConcurrentMap for thread safe concurrent access.
use an enum for a Singleton.
Both of these were added in Java 5.0.
public enum MyClassCache {
INSTANCE;
private final Map<String, MyClass> cache = new ConcurrentHashMap<>();
public boolean hasId(String id) {
return cache.containsKey(id);
}
public MyClass get(String id) throws IllegalStateException {
MyClass ret = cache.get(id);
if (ret == null) throw new IllegalStateException(id);
return ret;
}
public MyClass getOrCreate(String id) throws IllegalStateException {
MyClass ret = cache.get(id);
if (ret == null) {
synchronized (cache) {
ret = cache.get(id);
if (ret == null) {
cache.put(id, ret = new MyClass(id));
}
}
}
return ret;
}
}
In Java 8 you can use computeIfAbsent
public MyClass getOrCreate(String id) {
return cache.computeIfAbsent(id, MyClass::new);
}
Am I right that the core of this question is the difference between:
public void ejbCreate1(String id) throws Exception {
try {
m_c = Singleton.getInstance().getObj(id);
} catch (Exception e) {
synchronized (Singleton.getInstance()) {
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
} else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
and
public void ejbCreate2(String id) throws Exception {
synchronized (Singleton.getInstance()) {
try {
m_c = Singleton.getInstance().getObj(id);
} catch (Exception e) {
//check again
if (!Singleton.getInstance().hasObj(id)) {
m_c = new MyClass(id);
Singleton.getInstance().addObj(id, m_c);
} else {
m_c = Singleton.getInstance().getObj(id);
}
}
}
}
in Java-6 that can cause the first to hang and the second to work fine.
Clearly the primary difference is that getObj might be called by two different threads at the same time, and may even be called while another threads is creating the new object.
From Is it safe to get values from a java.util.HashMap from multiple threads (no modification)? it is likely that you are not in that situation. Conclusion is that one thread is readng from the Map (perhaps o = (MyClass) this.objCache.get(id);) while another is writing to the map by calling addObj. This is clearly a recipe for the read to crash and burn.
See Is a HashMap thread-safe for different keys? for details about the potential sinkholes.