Java serialization causes concurrency modification exception - java

My program updates several hundred objects stored in an ArrayList about one hundred times per second. I've implemented Java's built in serialization, and it works well except when an attempt to serialize is made when the objects are going at it, in which case I may have to serialize a half dozen times before it works (each failed attempt throws an exception). I tried marking the arraylist as transient, but then when I loaded the serialization file, a null pointer exception is thrown. So I tried initializing the transient arraylist in the no args constructor, which did nothing to help. What do I do? Thanks.

First make sure you've synchronized access to your ArrayList, e.g. when you initialize it:
List<String> list = Collections.synchronizedList(new ArrayList<String>());
When you need to serialize it, grab a copy that will be consistent due to the synchronization:
List<String> copy = new ArrayList<String>(list);
Now you can safely serialize out this copy without blocking access to the primary list.

You can't iterate with foreach statement and modify your table.
Try to use
for (int i =0;i<arra.length;i++)
instead.

Copy the ArrayList to a new instance (shallow copy with new ArrayList<>() and serialize that.

Use the Iterator if you are traversing through the collection and concurrently modifying it.

Assuming you really don't want or need the list contents serialised declare your list member:
private transient final List<?> things = new ArrayList<Object>();
You will always have a non-null list to work with.
That being said, from the sound of it your updates to the list itself may need to be thought about regarding other thread-safety issues such data-races and visibility issues.

Related

What is the best way in terms of space efficiency to make a List of objects immutable?

Prompted by the example provided at 37:19 of this talk by Stuart Marks on Java Collections, I was wondering what is the best way to make a List of objects immutable from a space efficiency perspective.
In my example, I have a List of objects that I retrieve from a database:
List<MyObject> myObjects = myRepository.getMyObjectsThatFitCriteria();
To make this List immutable I can think of three ways to do it
Wrap it in Collections.unModifiableList() but this creates another object and the underlying list itself is still modifiable
Stream over the myObjects list and collect it to an unmodifiable list but this might have a performance impact, particularly if the list is large
Use the List.copyOf() static factory method introduced in Java 9 but this creates another copy of the myObjects list, impacting memory and storage.
As mentioned by #VGR in the comment, Collections.unmodifiableList will not copy the elements into a new list, but rather wrap it and prevent modifications on it.
If you're using Spring Data JPA for repository support, it's a good idea to leverage its support for streams: https://www.baeldung.com/spring-data-java-8
Streams are a good way to avoid large memory consumption if the list is large. It does not change the source collection and allows lazy consumption.
Wrap it in Collections.unModifiableList() but this creates another object and the underlying list itself is still modifiable.
You still need to create a list so there is no way around that. But you can always reassign to the same list to effectively remove the reference from access.
list = Collections.unModifiableList(list);
The original list internally is simply referred to (thus not copied) for immutable methods like size(). Any other methods that would allow changes are overridden with methods that throw exceptions if they are invoked. So the overhead is minimal.
Note that unless the contained objects are immutable, they are still subject to alteration.

Is it possible to find out if some list is fixed size or not?

Is it possible to find out if some a list is fixed size or not?
I mean, for example this code:
String[] arr = {"a", "b"};
List<String> list = Arrays.asList(array);
returns fixed size List backed by an array. But is it possible to understand programmatically if List is fixed-size or not without trying to add/remove elements and catching the exception? For example:
try {
list.add("c");
}
catch(UnsupportedOperationException e) {
// Fixed-size?
}
A list created from a String[] by
List<String> list = Arrays.asList(array);
will have Arrays as enclosing class, while one created by for example new ArrayList() won't have the enclosing class. So the following should work to check if the List was produced as a result of calling Arrays.toList():
static <T> boolean wasListProducedAsAResultOfCallingTheFunctionArrays_asList(List<T> l) {
return Arrays.class.equals(l.getClass().getEnclosingClass());
}
Beware that this method relies on undocumented behavior. It will break if they added another nested List subclass to the Arrays class.
Is it possible to find out if some list is fixed size or not?
In theory - No. Fixed sizedness is an emergent property of the implementation of a list class. You can only determine if a list has that property by trying to add an element.
And note that a simple behavioral test would not reliably distinguish between a fixed sized list and a bounded list or a list that was permanently or temporarily read-only.
In practice, a fixed sized list will typically have a different class to an ordinary one. You can test the class of an object to see if it or isn't a specific class. So if you understand what classes would be used to implement fixed sized lists in your code-base, then you can test if a specific list is fixed sized.
For example the Arrays.asList(...) method returns a List object whose actual class is java.util.Arrays.ArrayList. That is a private nested class, but you could use reflection find it, and then use Object.getClass().equals(...) to test for it.
However, this approach is fragile. Your code could break if the implementation of Arrays was modified, or if you started using other forms of fixed sized list as well.
No.
The List API is identical regardless of whether a List is expandable or not, something that was deliberate.
There is also nothing in the List API that allows you to query it to determine this feature.
You can't completely reliably determine this information by reflection, because you will be depending on internal details of the implementation, and because there is an unbounded number of classes that are potentially fixed-size. For example, in addition to Arrays.asList, there is also Arrays.asList().subList, which happens to return a different class. There can also be wrappers around the base list like Collections.checkedList, Collections.synchronizedList and Collections.unmodifiableList. There are also other fixed-size lists: Collections.emptyList, Collections.singletonList, and Collections.nCopies. Outside the standard library, there are things like Guava's ImmutableList. It's also pretty trivial to hand-roll a list for something by extending AbstractList (for a fixed-size list you need only implement the size() and get(int) methods).
Even if you detect that your list is not fixed-size, the specification of List.add allows it to refuse elements for other reasons. For example, Collections.checkedList wrappers throw a ClassCastException for elements of unwanted type.
And even if you know your list is expandable, and allows arbitrary elements, that doesn't mean you want to use it. Perhaps it's synchronized, or not synchronized, or isn't serializable, or it's a slow linked list, or has some other quality that you don't want.
If you want control over the type, mutability, serializability, or thread-safety of the list, or you want to be sure that no other code has kept a reference to it, the practice is that you create a new one yourself. It's not expensive to do so when unnecessary (memcopies are blazing fast), and it lets you reason more definitely about your code will actually do at runtime. If you'd really like to avoid creating unnecessary copies, try whitelisting instead of blacklisting list classes. For example:
if (list.getClass() != ArrayList.class) {
list = new ArrayList<>(list);
}
(Note: That uses getClass instead of instanceof, because instanceof would also be true for any weird subclasses of ArrayList.)
There are immutable collections in java-9, but there is still no common #Immutable annotation for example or a common marker interface that we could query to get this information.
The simplest way I can think of would be simply to get the name of the class of such an instance:
String nameList = List.of(1, 2, 3).getClass().getName();
System.out.println(nameList.contains("Immutable"));
but that still relies on internal details, since it queries the name of the common class ImmutableCollections, that is not public and obviously can change without notice.

Java: ConcurrentModificationException, 3 threads, different lists, same objects

I have the following situation:
In a main function if some controller class I retrieve 10 product objects from my DB. These are hold in an ArrayList object.
Afterwards I create three classes which extend Runnable and I give to each class the product-ArrayList into the constructor.
In each of the constructors is a new local ArrayList created and the objects in the product-ArrayList are added:
this.products = new ArrayList();
products.addAll(productListParam);
Afterwards I start each of three threads and they iterate over their local products-lists and also modify it.
I'm getting a ConcurrentModificationException while iterating over the local product ArrayList..
Why is this happening? I was assuming that if I create a complete new list in each thread I can modify this locally as much as I want without caring about the other threads - am I right? Or does the removal of some object from a local list affect the pbjects somehow so that the other threads throw the Concurrent Modification Exception?
Actually the stacktrace looks like:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at com.x.y.class.method(Classname.java:326)
and Classname.java at 326 looks like:
325:List<Product> productsToDelete = new ArrayList();
326:for(Product p: products){
...
if(xy){
productsToDelete.add(p);
}
}
products.removeAll(productsToRemove);
Maybe someone has a hint for me what I'm doing wrong?
Edit: Inside the loop the product object p is just used for reading. Additionally there are no modifications done to the products-ArrayList. They are only added to a second "toBeRemoved" list to remove them later after the for-loop finished.. I edited the code above.
I think I'm mostly interested in the question if I can create several list-objects, add the same product-objects to each of them via the addAll()-method and then can to anything with it in each thread without caring about the other threads?!
You can't modify the Collection inside an enhanced for loop that iterates over its elements. Not even if you only have a single thread.
You didn't include the code inside the enhanced for loop, but if what you need to do inside it is remove elements from the list, you can use an explicit iterator.
Iterator<Product> iter = products.iterator();
While (iter.hasNext() {
Product p = iter.next();
....
if (some condition)
iter.remove();
....
}
Sorry guys to bother you, I did a bad beginner fault!
I was setting the mentioned product-ArrayList manually later from some other code basis and did overwrite the new ArrayList.. so all threads again used only one ArrayList and the ConcurrentModificationException occured.
As you see within this example, always double check your code :)
Sorry for bothering you..

What is the use of singletonList?

I was looking around for some elegant solution to removing null values from a List. I came across the following post, which says I can use list.removeAll(Collections.singletonList(null));
This, however, throws an UnsupportedOperationException, which I'm assuming is because removeAll() is attempting to do some mutative operation on the immutable singleton collection. Is this correct?
If this is the case, what would be a typical use of this singletonList? To represent a collection of size 1 when you're sure you don't want to actually do anything with the collection?
Thanks in advance.
It works like a charm:
List<String> list = new ArrayList<String>();
list.add("abc");
list.add(null);
list.add("def");
list.removeAll(Collections.singletonList(null));
System.out.println(list); //[abc, def]
Indeed Collections.singletonList(null) is immutable (which is unfortunately hidden in Java[1]), but the exception is thrown from your list variable. Apparently it is immutable as well, like in example below:
List<String> list = Arrays.asList("abc", null, "def");
list.removeAll(Collections.singletonList(null));
This code will throw an UnsupportedOperationException. So as you can see singletonList() is useful in this case. Use it when client code expects a read-only list (it won't modify it) but you only want to pass one element in it. singletonList() is (thread-)safe (due to immutability), fast and compact.
[1] E.g. in scala there is a separete hierarchy for mutable and immutable collections and API can choose whether it accept this or the other (or both, as they have common base interfaces)
To answer your actual question :
what would be a typical use of this singletonList? To represent a collection of size 1 when you're sure you don't want to actually do anything with the collection?
The typical use is if you have one element and want to pass it to a method that accepts a List, ie
public void registerUsers(List<User> users) {...}
User currentUser = Login Manager.getCurrentUser();
registerUsers(Collections.singletonList(currentUser));
The removeAll() is a special case for this.
Has your list been protected with
Collections.unmodifiableList(list)
Because if you have protected it and try to modify it later you get that error.

ArrayList - add "same" objects (same => equals, hashCode), Threads

Ive got one question. What happens when I try to add the "same" object twice to an ArrayList. With "the same" I mean an object of an individual class, which is identified as the same with equals() and hashCode(). It has different values for most of the member variables and was created from maybe different threads, but for equals() and hashCode() its the "same".
Does the second object then replace the first object?
Also, what happens if two threads try to add those objects exactly at the same time to the ArrayList? Is this even possible? If yes, what happens?
Thank you! :-)
[EDIT] Thanks for all the answers! Should I use synchronizedList then rather then using "synchronize(list){}"? --> I read the docs, even with synchronizedList, for iterating synchronize(list) shall be used
[EDIT2]
Can a synchronizedList be declared as a member variable? I tried, but it didnt work.
No, ArrayList doesn't attempt to detect duplicates at all - you can have an ArrayList with the exact same reference appearing multiple times. If you want a collection to avoid duplicates, you need a Set implementation - and if you also want to preserve insertion order, you probably want LinkedHashSet.
Note, however, that without locking ArrayList should not be mutated from multiple threads in the first place - it's simply not meant to be a thread-safe collection in that way. Several threads can read from an ArrayList without synchronization, but not mutate it. From the docs:
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList method. This is best done at creation time, to prevent accidental unsynchronized access to the list
If you want to mutate a collection from multiple threads without locking, I suggest you look at the collections in java.util.concurrent.
Does the second object then replace
the first object?
No, most developers do explicit checks
if(!list.contains(foo)){
list.add(foo);
}
Also, what happens if two threads try
to add those objects exactly at the
same time to the ArrayList? Is this
even possible? If yes, what happens?
Yes, this is possible. If multiple threads write to/read from the same ArrayList, then use the synchronized keyword whenever you access this list
public List<Foo> getFoos(){
synchronized(list){
return list;
}
}
public void addFoo(Foo foo){
synchronized(list){
list.add(foo);
}
}
EDIT
As someone pointed out, I suppose checking whether or not the ArrayList contains the object to be added is quite expensive. If you want to ensure that the object is only added once, I'd follow the recommendation made below of using a LinkedHashSet. According to the API, when attempting to add to this data structure it
Adds the specified element to this set
if it is not already present. More
formally, adds the specified element e
to this set if this set contains no
element e2 such that (e==null ?
e2==null : e.equals(e2)). If this set
already contains the element, the call
leaves the set unchanged and returns
false.
It will allow to add simply. List has nothing to do with hashCode(), equals() while insertion it doesn't care for duplicate.
ArrayList isn't thread safe so you might not get desired result. you can have synchronizedList from Collections class
An ArrayList can contain multiple references to the same exact object (identity equivalence). It doesn't check equals() or hashCode() when adding objects.
You will just end up with two references in your ArrayList.
ArrayList is NOT thread-safe...so the behaviour if you try to have two threads add at the same time is undefined. Maybe try using a SynchronizedList if you want to do something like that.
If you try to add the same object twice, it will work, or if you try to add 2 objects with everything the same, it will still work. It is not best practice to do that because its harder to maintain the list.
overall: you shouldn't do it

Categories

Resources