How List<> object reference works? - java

I have List<CapturedImage> capturedImageList = assingedFromSomewhere();
What will happen if I delete element 0 of capturedImageList which is currently being processed by a separate Thread?
// Procesing a Thread
capturedImage.deleteImageFile(capturedImageList.get(0).getAbsolutePath());
if (capturedImage.saveToDisk(bitmap_original)) {
// Note : Thred process in not completed yet
capturedImageList.remove(0);
capturedImageList.add(0, capturedImage);
}
Will the file will get deleted?
If so, how is the object reference is working here?

I haven't tried this but i believe you will encounter a concurrent modification exception,
if you try to manipulate a resource which is already in use.. instead you can use a
CopyOnWriteArrayList

Related

Kotlin ConcurrentModificationException: when finding object from a list (Without removing any object or touching original list)

I have a MutableList of "DisplayableMessage" unmanaged objects, and I want to find an object from this MutableList by property "messageId".
The code is in onBindViewHolder of a RecyclerViewAdapter:
val displayableMessage = displayableMessages?.find { item -> item?.messageId == message.id }
When the main thread is running this line of code, The exception "java.util.ConcurrentModificationException" is raised.
The last 5 line of stack:
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at MessagesAdapter.onBindViewHolder(MessagesAdapter.kt:279)
at MessagesAdapter.onBindViewHolder(MessagesAdapter.kt:81)
at androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:7059)
at androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:7101)
MessagesAdapter.kt:279 is the code that I mentioned above.
As you see I'm not removing the list object nor touching the original list.
Edit v1:
displayableMessages is referencing a mutable list that is created from detached realm results (This creation happens in another thread).
The code for detaching realm results:
val copiedMessages = Realm.getDefaultInstance().copyFromRealm(realmResults)
After this code, MutableList "list" is created from copiedMessages in another thread (because it includes reading from DB) and then displayableMessages is set to "list".
Then I use the main thread to notify that dataset was changed:
GlobalScope.launch(Dispatchers.Main) {
notifyDataSetChanged()
}
All these codes are run every time realmResults changes.

Why am i getting ConcurrentModificationException on this unmodifiableSet?

I'm getting a java.util.ConcurrentModificationException on the line where the for-loop starts (see comment in code).
Why am i getting ConcurrentModificationException on this unmodifiableSet?
final Set<Port> portSet = Collections.unmodifiableSet(node.getOpenPorts());
if (!portSet.isEmpty()) {
StringBuilder tmpSb = new StringBuilder();
for (Port pp : portSet) { // <------- exception happening here
tmpSb.append(pp.getNum()).append(" ");
}
}
I've never witnessed this, but I'm getting crash reports from Google.
Something must be modifying the underlying set; i.e. the set returned by node.getOpenPorts().
Instead of wrapping the set with an "unmodifiable" wrapper, you could copy it.
final Set<Port> portSet = new HashSet<>(node.getOpenPorts());
But as a commenter (#Slaw) pointed out, that just moves the iteration inside the constructor and you would still get CCMEs.
The only real solutions are:
Change the implementation of the node class to use a concurrent set class for the port list that won't throw CCMEs if the collection is mutated while you are iterating it.
Change the implementation of the node class to return a copy of the port list. Deal with the updates-while-copying race condition with some internal locking.
Put a try / catch around the code and repeat the operation if you get a CCME
I've never witnessed this, but I'm getting crash reports from Google.
Yes. The problem only occurs if this code is executed while the open port list is changing.

ConcurrentModificationException crashes my app

My Android app has an IntentService where it requests a list of MessageThreads objects from Facebook, parses the JSON response to build an ArrayList of the objects:
ArrayList<MessageThread> mMessageThreads = new ArrayList<MessageThread>();
Then it calls FB again in the same service, get the names for the MessageThread ids and matches them with the MessageThread objects. At this point I have an ArrayList with complete MessageThread objects and I insert them into an SQLite db.
// save to db and broadcast
for (MessageThread message : mMessageThreads) {
((FBClientApplication)getApplication()).getMessagesData().insertOrIgnore(message.toContentValues();
}
where:
public void insertOrIgnore(ContentValues values) {
SQLiteDatabase db = this.dbHelper.getWritableDatabase();
db.insertWithOnConflict(TABLE, null, values, SQLiteDatabase.CONFLICT_IGNORE);
}
Via ACRA reports I see that intermittently the line
for (MessageThread message : mMessageThreads)
throws an ConcurrentModificationException and the app forcloses. I haven't been able to isolate under what conditions. I read about this Exception and as I understand it it happens when we remove items from an ArrayList while iterating over it, but I'm not removing items from the list. Any pointers to help with this problem are greatly appreciated.
It also happens when you add items to an ArrayList while iterating over it, which it looks like you might do in this code.
In general, it's any "structural modification" that occurs to the ArrayList that can cause a CME while iterating.
What you can try to do is when you iterates your Collection instead of using the original you can make a copy right there, so you will have something like:
for (MessageThread message : new List<MessageThread>(mMessageThreads))
That will help you to avoid CuncurrentModificationException.
Now if you really want to get fancy you can protect your code using synchronized blocks such as:
synchronized(mMessageThreads){
for (MessageThread message : new List<MessageThread>(mMessageThreads)){
...
}
With this last pice of code you will restrict the access to mMessageThreads, if somebody it's using it it will get locked, so if somebody else wants to use it needs to wait until the first one is done.

Deal with concurrent modification on List without having ConcurrentModificationException

I have a stateful EJB which calls an EJB stateless method of Web parsing pages.
Here is my stateful code :
#Override
public void parse() {
while(true) {
if(false == _activeMode) {
break;
}
for(String url : _urls){
if(false == _activeMode) {
break;
}
for(String prioritaryUrl : _prioritaryUrls) {
if(false == _activeMode)
break;
boursoramaStateless.parseUrl(prioritaryUrl);
}
boursoramaStateless.parseUrl(url);
}
}
}
No problem here.
I have some asynchronously call (with JMS) that add to my _urls variable (a List) some value. Goal is to parse new url inside my infinity loop.
I receive ConcurrentModificationException when I try to add new url in my List via JMS onMessage method but it seems to be working because this new url is parsed.
When I try to wrap a synchronized block :
while(true){
synchronized(_url){
// code...
}
}
My new url is never parsed, I expected to be parsed after a for() loop finished...
So my question is : how can I modify List when it's accessed inside a loop without having ConcurrentModificationException please ?
I just want 2 threads to modify some shared resource at same time without synchronized block...
You may want a CopyOnWriteArrayList.
For (String s : urls) uses an Iterator internally. The iterator checks for concurrent modification so that its behavior is well defined.
You can use a for(int i= ... loop. This way, no exception is thrown, and if elements are only added to the end of the List, you still get a consistent snapshot (the list as it exists at some time during the iteration). If the elements in the list are moved around, you may get missing entries.
If you want to use synchronised, you need to synchronise on both ends, but that way you lose concurrent reads.
If you want concurrent access AND consistent snapshots, you can use any of the collections in the java.util.concurrent package.
CopyOnWriteArrayList has already been mentioned. The other interesting are LinkedBlockingQueue and ArrayBlockingQueue (Collections but not Lists) but that's about all.
ok thank you guys.
So I made some modifications.
1) added iterator and leaving synchronized block (inside parse() function and around addUrl() function which add new url to my List)
--> it's work like a charm, no ConcurrentModificationException launched
2) added iterator and removed synchronized blocks
--> ConcurrentModificationException is still launched...
For now, I will read more about your answers and test your solutions.
Thank you again guys
First, forget about synchronized when running into Java EE container. It bothers the container to optimize threads utilization and will not work in clustered environment.
Second, it seems that your design is wrong. You should not update private field of the bean using JMS. This thing causes ConcurrentModificationException. You probably should modify your bean to retrieve the collection from database and your MDB to store the URL into the Database.
Other, easier for you solution is the following.
Retrieve the currently existing URLs and copy them to other collection. Then iterate over this collection. When the global collection is updated via JMS the update is not visible in the copied collection, so no exceptions will be thrown:
while(true) {
for (String url : copyUrls(_prioritaryUrls)) {
// deal with url
}
}
private List<String> copyUrls(List<Stirng> urls) {
return new ArrayList<String>(urls); // this create copy of the source list
}
//........
public void onMessage(Message message) {
_prioritaryUrls.add(((TextMessage)message).getText());
}

What does eclipse do when you inspect variables (while debugging)

I have an instance of org.hibernate.envers.entities.mapper.relation.lazy.proxy.ListProxy that is causing some grief: whenever I programmatically try to access it I get a null pointer exception (ie calling list.size()) but when I first inspect the object using Eclipse's variable inspector I see Hibernate generate a SQL statement and the list changes dynamically. Then everything works. How can I do the same thing programmatically? I've tried list.toString() but that doesn't seem to help.
Update 1
Don't know if this helps but when I first click on the list instance I see in the display:
com.sun.jdi.InvocationException occurred invoking method.
Then database query runs and when I click again I get the correct .toString() result.
Update 2
Here is the original exception I get (when I don't inspect the element in debug mode).
java.lang.NullPointerException
at org.hibernate.envers.query.impl.EntitiesAtRevisionQuery.list(EntitiesAtRevisionQuery.java:72)
at org.hibernate.envers.query.impl.AbstractAuditQuery.getSingleResult(AbstractAuditQuery.java:104)
at org.hibernate.envers.entities.mapper.relation.OneToOneNotOwningMapper.mapToEntityFromMap(OneToOneNotOwningMapper.java:74)
at org.hibernate.envers.entities.mapper.MultiPropertyMapper.mapToEntityFromMap(MultiPropertyMapper.java:118)
at org.hibernate.envers.entities.EntityInstantiator.createInstanceFromVersionsEntity(EntityInstantiator.java:93)
at org.hibernate.envers.entities.mapper.relation.component.MiddleRelatedComponentMapper.mapToObjectFromFullMap(MiddleRelatedComponentMapper.java:44)
at org.hibernate.envers.entities.mapper.relation.lazy.initializor.ListCollectionInitializor.addToCollection(ListCollectionInitializor.java:67)
at org.hibernate.envers.entities.mapper.relation.lazy.initializor.ListCollectionInitializor.addToCollection(ListCollectionInitializor.java:39)
at org.hibernate.envers.entities.mapper.relation.lazy.initializor.AbstractCollectionInitializor.initialize(AbstractCollectionInitializor.java:67)
at org.hibernate.envers.entities.mapper.relation.lazy.proxy.CollectionProxy.checkInit(CollectionProxy.java:50)
at org.hibernate.envers.entities.mapper.relation.lazy.proxy.CollectionProxy.size(CollectionProxy.java:55)
at <MY CODE HERE, which checks list.size()>
Final Solution (Actually more of a temporary hack)
boolean worked = false;
while (!worked) {
try {
if(list.size() == 1) {
// do stuff
}
worked = true;
} catch (Exception e) {
// TODO: exception must be accessed or the loop will be infinite
e.getStackTrace();
}
}
Well what happends there is you're seing Hibernate's lazy loading in deep action :)
Basically hibernate loads proxy classes for you lazily associated relations, such that instead of a List of classes C you get a List (actually a PersistenceBag implementation) of Hibernate autogenerated proxie for your C class. THis is hibernate's way of deferring load of that association's values until they are actually accessed. So that's why when you access it in the eclipse debugger (which basically accesses an instance's fields/methids via introspection) you see the sql hibernate triggers to fetch the needed data.
The trick here is that depending on WHEN you access a lazy collection you might get different results. If you access it using the eclipse debugger you're more likely still in the Hibernate session that started loading that thing, so everything works as expected, an sql is (lazily) triggered when the thing is accessed and the data is loaded). Problem is that if you wanna access that same data in your code, but at a point where the session is already closed, you'll either get a LazyInitializationException or null (the latter if you're using some library for cleaning put hibenrate proxises such as Gilead)

Categories

Resources