I've got two question about this code:
import java.util.*;
public class TestClass {
private static List<String> list;
public static void main(String[] argv) {
list = generateStringList(new Random(), "qwertyuioasdfghjklzxcvbnmPOIUYTREWQLKJHGFDSAMNBVCXZ1232456789", 50, 1000);
// Collections.sort(list, new Comparator<String>() {
// public int compare(String f1, String f2) {
// return -f1.compareTo(f2);
// }
// });
for (int i = 0; i < 500; i++) {
new MyThread(i).start();
}
}
private static class MyThread extends Thread {
int id;
MyThread(int id) { this.id = id; }
public void run() {
Collections.sort(list, new Comparator<String>() {
public int compare(String f1, String f2) {
return -f1.compareTo(f2);
}
});
for (Iterator it = list.iterator(); it.hasNext();) {
String s = (String) it.next();
try {
Thread.sleep(10 + (int)(Math.random()*100));
}catch (Exception e) { e.printStackTrace(); }
System.out.println(id+" -> "+s);
}
}
}
public static List<String> generateStringList(Random rng, String characters, int length, int size)
{
List<String> list = new ArrayList<String>();
for (int j = 0; j < size; j++) {
char[] text = new char[length];
for (int i = 0; i < length; i++)
{
text[i] = characters.charAt(rng.nextInt(characters.length()));
}
list.add(new String(text));
}
return list;
}
}
Running this code on java 1.8.0_45 i got java.util.ConcurrentModificationException
.
1) Why I got the exception also if I decomment the sort before the thread.start?
2) Why I only got the exception on java 1.8.0_45? On 1.6.0_45, 1.7.0_79, 1.8.0_5 it works fine.
@nbokmans already nailed the general reason why you get that exception. However, it's true that this seems to be version dependant. I'll fill in why you get that in java 8.0_45 but not 1.6.0_45, 1.7.0_79, 1.8.0_5.
This is due to fact that Collections.sort() was changed in java 8.0_20. There's an in-depth article about it here. In the new version, sort, according to the article, is like this:
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
Like the article explains:
Contrary to the old Collections.sort, this implementation modifies the modCount of the collection (line 7 above) once the list has been sorted, even if the structure itself didn’t really change (still the same number of elements).
So it will do an internal change even if the collection is already sorted, whereas before that change it didn't do that. That's why you're getting an exception now.
The actual fix is to not to sort a collection using multiple threads at the same time. You shouldn't do that.
A ConcurrentModificationException is thrown by methods that have detected concurrent (i.e. in a separate thread) modification of an object when such modification is not permissible.
The reason you're getting this exception is because you are modifying (sorting) the collection in a separate thread and iterating it.
I quote from the ConcurrentModificationException javadoc:
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances.
Source
In your code, you are starting 500 threads that each sort and iterate over the list.
Try sorting the list before you start your threads, and remove the call to Collections#sort from MyThread's #run().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With