I understand that modification of a List is dangerous while iterating over it, hence ConcurrentModificationException is thrown.
But I do not understand what can be a possible issue if a thread adds elements to the end of the List while another thread is iterating over it.
I don't think that's the reason though, as you can also have inconsistencies when performing two operations on an unsynchronized list in two different threads when you don't iterate at all.
Despite its name, ConcurrentModificationException has nothing to do with multiple threads, but may even occur when iteration and modification occur in the same thread.
Let's say you iterate over all elements in a collection using Iterator.next(), add another element to the collection, and then call hasNext() on the iterator. Should it return true because there is another element at the end? Should it return false because it already reached the end of the list once?
There's no rule that works well for all iterator implementations. For instance, most Set implementations don't have an ordering, so there is no notion of where the element will be added or how it will affect the iterator.
To avoid insidious bugs caused by subtle differences in iterator behavior, the designers chose to make most iterators throw an exception when they detect that the collection has been modified while the iterator is still in use.