28 |
|
import java.util.RandomAccess; |
29 |
|
import java.util.Spliterator; |
30 |
|
import java.util.Spliterators; |
31 |
– |
import java.util.concurrent.locks.ReentrantLock; |
31 |
|
import java.util.function.Consumer; |
32 |
|
import java.util.function.Predicate; |
33 |
|
import java.util.function.UnaryOperator; |
73 |
|
implements List<E>, RandomAccess, Cloneable, java.io.Serializable { |
74 |
|
private static final long serialVersionUID = 8673264195747942595L; |
75 |
|
|
76 |
< |
/** The lock protecting all mutators */ |
77 |
< |
final transient ReentrantLock lock = new ReentrantLock(); |
76 |
> |
/** |
77 |
> |
* The lock protecting all mutators. (We have a mild preference |
78 |
> |
* for builtin monitors over ReentrantLock when either will do.) |
79 |
> |
*/ |
80 |
> |
final transient Object lock = new Object(); |
81 |
|
|
82 |
|
/** The array, accessed only via getArray/setArray. */ |
83 |
|
private transient volatile Object[] array; |
386 |
|
* @throws IndexOutOfBoundsException {@inheritDoc} |
387 |
|
*/ |
388 |
|
public E set(int index, E element) { |
389 |
< |
final ReentrantLock lock = this.lock; |
388 |
< |
lock.lock(); |
389 |
< |
try { |
389 |
> |
synchronized (lock) { |
390 |
|
Object[] elements = getArray(); |
391 |
|
E oldValue = get(elements, index); |
392 |
|
|
400 |
|
setArray(elements); |
401 |
|
} |
402 |
|
return oldValue; |
403 |
– |
} finally { |
404 |
– |
lock.unlock(); |
403 |
|
} |
404 |
|
} |
405 |
|
|
410 |
|
* @return {@code true} (as specified by {@link Collection#add}) |
411 |
|
*/ |
412 |
|
public boolean add(E e) { |
413 |
< |
final ReentrantLock lock = this.lock; |
416 |
< |
lock.lock(); |
417 |
< |
try { |
413 |
> |
synchronized (lock) { |
414 |
|
Object[] elements = getArray(); |
415 |
|
int len = elements.length; |
416 |
|
Object[] newElements = Arrays.copyOf(elements, len + 1); |
417 |
|
newElements[len] = e; |
418 |
|
setArray(newElements); |
419 |
|
return true; |
424 |
– |
} finally { |
425 |
– |
lock.unlock(); |
420 |
|
} |
421 |
|
} |
422 |
|
|
428 |
|
* @throws IndexOutOfBoundsException {@inheritDoc} |
429 |
|
*/ |
430 |
|
public void add(int index, E element) { |
431 |
< |
final ReentrantLock lock = this.lock; |
438 |
< |
lock.lock(); |
439 |
< |
try { |
431 |
> |
synchronized (lock) { |
432 |
|
Object[] elements = getArray(); |
433 |
|
int len = elements.length; |
434 |
|
if (index > len || index < 0) |
446 |
|
} |
447 |
|
newElements[index] = element; |
448 |
|
setArray(newElements); |
457 |
– |
} finally { |
458 |
– |
lock.unlock(); |
449 |
|
} |
450 |
|
} |
451 |
|
|
457 |
|
* @throws IndexOutOfBoundsException {@inheritDoc} |
458 |
|
*/ |
459 |
|
public E remove(int index) { |
460 |
< |
final ReentrantLock lock = this.lock; |
471 |
< |
lock.lock(); |
472 |
< |
try { |
460 |
> |
synchronized (lock) { |
461 |
|
Object[] elements = getArray(); |
462 |
|
int len = elements.length; |
463 |
|
E oldValue = get(elements, index); |
472 |
|
setArray(newElements); |
473 |
|
} |
474 |
|
return oldValue; |
487 |
– |
} finally { |
488 |
– |
lock.unlock(); |
475 |
|
} |
476 |
|
} |
477 |
|
|
498 |
|
* recent snapshot contains o at the given index. |
499 |
|
*/ |
500 |
|
private boolean remove(Object o, Object[] snapshot, int index) { |
501 |
< |
final ReentrantLock lock = this.lock; |
516 |
< |
lock.lock(); |
517 |
< |
try { |
501 |
> |
synchronized (lock) { |
502 |
|
Object[] current = getArray(); |
503 |
|
int len = current.length; |
504 |
|
if (snapshot != current) findIndex: { |
524 |
|
len - index - 1); |
525 |
|
setArray(newElements); |
526 |
|
return true; |
543 |
– |
} finally { |
544 |
– |
lock.unlock(); |
527 |
|
} |
528 |
|
} |
529 |
|
|
540 |
|
* ({@code fromIndex < 0 || toIndex > size() || toIndex < fromIndex}) |
541 |
|
*/ |
542 |
|
void removeRange(int fromIndex, int toIndex) { |
543 |
< |
final ReentrantLock lock = this.lock; |
562 |
< |
lock.lock(); |
563 |
< |
try { |
543 |
> |
synchronized (lock) { |
544 |
|
Object[] elements = getArray(); |
545 |
|
int len = elements.length; |
546 |
|
|
557 |
|
fromIndex, numMoved); |
558 |
|
setArray(newElements); |
559 |
|
} |
580 |
– |
} finally { |
581 |
– |
lock.unlock(); |
560 |
|
} |
561 |
|
} |
562 |
|
|
577 |
|
* recent snapshot does not contain e. |
578 |
|
*/ |
579 |
|
private boolean addIfAbsent(E e, Object[] snapshot) { |
580 |
< |
final ReentrantLock lock = this.lock; |
603 |
< |
lock.lock(); |
604 |
< |
try { |
580 |
> |
synchronized (lock) { |
581 |
|
Object[] current = getArray(); |
582 |
|
int len = current.length; |
583 |
|
if (snapshot != current) { |
593 |
|
newElements[len] = e; |
594 |
|
setArray(newElements); |
595 |
|
return true; |
620 |
– |
} finally { |
621 |
– |
lock.unlock(); |
596 |
|
} |
597 |
|
} |
598 |
|
|
634 |
|
*/ |
635 |
|
public boolean removeAll(Collection<?> c) { |
636 |
|
if (c == null) throw new NullPointerException(); |
637 |
< |
final ReentrantLock lock = this.lock; |
664 |
< |
lock.lock(); |
665 |
< |
try { |
637 |
> |
synchronized (lock) { |
638 |
|
Object[] elements = getArray(); |
639 |
|
int len = elements.length; |
640 |
|
if (len != 0) { |
652 |
|
} |
653 |
|
} |
654 |
|
return false; |
683 |
– |
} finally { |
684 |
– |
lock.unlock(); |
655 |
|
} |
656 |
|
} |
657 |
|
|
673 |
|
*/ |
674 |
|
public boolean retainAll(Collection<?> c) { |
675 |
|
if (c == null) throw new NullPointerException(); |
676 |
< |
final ReentrantLock lock = this.lock; |
707 |
< |
lock.lock(); |
708 |
< |
try { |
676 |
> |
synchronized (lock) { |
677 |
|
Object[] elements = getArray(); |
678 |
|
int len = elements.length; |
679 |
|
if (len != 0) { |
691 |
|
} |
692 |
|
} |
693 |
|
return false; |
726 |
– |
} finally { |
727 |
– |
lock.unlock(); |
694 |
|
} |
695 |
|
} |
696 |
|
|
709 |
|
Object[] cs = c.toArray(); |
710 |
|
if (cs.length == 0) |
711 |
|
return 0; |
712 |
< |
final ReentrantLock lock = this.lock; |
747 |
< |
lock.lock(); |
748 |
< |
try { |
712 |
> |
synchronized (lock) { |
713 |
|
Object[] elements = getArray(); |
714 |
|
int len = elements.length; |
715 |
|
int added = 0; |
726 |
|
setArray(newElements); |
727 |
|
} |
728 |
|
return added; |
765 |
– |
} finally { |
766 |
– |
lock.unlock(); |
729 |
|
} |
730 |
|
} |
731 |
|
|
734 |
|
* The list will be empty after this call returns. |
735 |
|
*/ |
736 |
|
public void clear() { |
737 |
< |
final ReentrantLock lock = this.lock; |
776 |
< |
lock.lock(); |
777 |
< |
try { |
737 |
> |
synchronized (lock) { |
738 |
|
setArray(new Object[0]); |
779 |
– |
} finally { |
780 |
– |
lock.unlock(); |
739 |
|
} |
740 |
|
} |
741 |
|
|
754 |
|
((CopyOnWriteArrayList<?>)c).getArray() : c.toArray(); |
755 |
|
if (cs.length == 0) |
756 |
|
return false; |
757 |
< |
final ReentrantLock lock = this.lock; |
800 |
< |
lock.lock(); |
801 |
< |
try { |
757 |
> |
synchronized (lock) { |
758 |
|
Object[] elements = getArray(); |
759 |
|
int len = elements.length; |
760 |
|
if (len == 0 && cs.getClass() == Object[].class) |
765 |
|
setArray(newElements); |
766 |
|
} |
767 |
|
return true; |
812 |
– |
} finally { |
813 |
– |
lock.unlock(); |
768 |
|
} |
769 |
|
} |
770 |
|
|
786 |
|
*/ |
787 |
|
public boolean addAll(int index, Collection<? extends E> c) { |
788 |
|
Object[] cs = c.toArray(); |
789 |
< |
final ReentrantLock lock = this.lock; |
836 |
< |
lock.lock(); |
837 |
< |
try { |
789 |
> |
synchronized (lock) { |
790 |
|
Object[] elements = getArray(); |
791 |
|
int len = elements.length; |
792 |
|
if (index > len || index < 0) |
808 |
|
System.arraycopy(cs, 0, newElements, index, cs.length); |
809 |
|
setArray(newElements); |
810 |
|
return true; |
859 |
– |
} finally { |
860 |
– |
lock.unlock(); |
811 |
|
} |
812 |
|
} |
813 |
|
|
823 |
|
|
824 |
|
public boolean removeIf(Predicate<? super E> filter) { |
825 |
|
if (filter == null) throw new NullPointerException(); |
826 |
< |
final ReentrantLock lock = this.lock; |
877 |
< |
lock.lock(); |
878 |
< |
try { |
826 |
> |
synchronized (lock) { |
827 |
|
Object[] elements = getArray(); |
828 |
|
int len = elements.length; |
829 |
|
if (len != 0) { |
840 |
|
} |
841 |
|
} |
842 |
|
return false; |
895 |
– |
} finally { |
896 |
– |
lock.unlock(); |
843 |
|
} |
844 |
|
} |
845 |
|
|
846 |
|
public void replaceAll(UnaryOperator<E> operator) { |
847 |
|
if (operator == null) throw new NullPointerException(); |
848 |
< |
final ReentrantLock lock = this.lock; |
903 |
< |
lock.lock(); |
904 |
< |
try { |
848 |
> |
synchronized (lock) { |
849 |
|
Object[] elements = getArray(); |
850 |
|
int len = elements.length; |
851 |
|
Object[] newElements = Arrays.copyOf(elements, len); |
854 |
|
newElements[i] = operator.apply(e); |
855 |
|
} |
856 |
|
setArray(newElements); |
913 |
– |
} finally { |
914 |
– |
lock.unlock(); |
857 |
|
} |
858 |
|
} |
859 |
|
|
860 |
|
public void sort(Comparator<? super E> c) { |
861 |
< |
final ReentrantLock lock = this.lock; |
920 |
< |
lock.lock(); |
921 |
< |
try { |
861 |
> |
synchronized (lock) { |
862 |
|
Object[] elements = getArray(); |
863 |
|
Object[] newElements = Arrays.copyOf(elements, elements.length); |
864 |
|
@SuppressWarnings("unchecked") E[] es = (E[])newElements; |
865 |
|
Arrays.sort(es, c); |
866 |
|
setArray(newElements); |
927 |
– |
} finally { |
928 |
– |
lock.unlock(); |
867 |
|
} |
868 |
|
} |
869 |
|
|
1130 |
|
* @throws IndexOutOfBoundsException {@inheritDoc} |
1131 |
|
*/ |
1132 |
|
public List<E> subList(int fromIndex, int toIndex) { |
1133 |
< |
final ReentrantLock lock = this.lock; |
1196 |
< |
lock.lock(); |
1197 |
< |
try { |
1133 |
> |
synchronized (lock) { |
1134 |
|
Object[] elements = getArray(); |
1135 |
|
int len = elements.length; |
1136 |
|
if (fromIndex < 0 || toIndex > len || fromIndex > toIndex) |
1137 |
|
throw new IndexOutOfBoundsException(); |
1138 |
|
return new COWSubList<E>(this, fromIndex, toIndex); |
1203 |
– |
} finally { |
1204 |
– |
lock.unlock(); |
1139 |
|
} |
1140 |
|
} |
1141 |
|
|
1166 |
|
// only call this holding l's lock |
1167 |
|
COWSubList(CopyOnWriteArrayList<E> list, |
1168 |
|
int fromIndex, int toIndex) { |
1169 |
+ |
// assert Thread.holdsLock(list.lock); |
1170 |
|
l = list; |
1171 |
|
expectedArray = l.getArray(); |
1172 |
|
offset = fromIndex; |
1175 |
|
|
1176 |
|
// only call this holding l's lock |
1177 |
|
private void checkForComodification() { |
1178 |
+ |
// assert Thread.holdsLock(l.lock); |
1179 |
|
if (l.getArray() != expectedArray) |
1180 |
|
throw new ConcurrentModificationException(); |
1181 |
|
} |
1182 |
|
|
1183 |
|
// only call this holding l's lock |
1184 |
|
private void rangeCheck(int index) { |
1185 |
+ |
// assert Thread.holdsLock(l.lock); |
1186 |
|
if (index < 0 || index >= size) |
1187 |
|
throw new IndexOutOfBoundsException("Index: "+index+ |
1188 |
|
",Size: "+size); |
1189 |
|
} |
1190 |
|
|
1191 |
|
public E set(int index, E element) { |
1192 |
< |
final ReentrantLock lock = l.lock; |
1256 |
< |
lock.lock(); |
1257 |
< |
try { |
1192 |
> |
synchronized (l.lock) { |
1193 |
|
rangeCheck(index); |
1194 |
|
checkForComodification(); |
1195 |
|
E x = l.set(index+offset, element); |
1196 |
|
expectedArray = l.getArray(); |
1197 |
|
return x; |
1263 |
– |
} finally { |
1264 |
– |
lock.unlock(); |
1198 |
|
} |
1199 |
|
} |
1200 |
|
|
1201 |
|
public E get(int index) { |
1202 |
< |
final ReentrantLock lock = l.lock; |
1270 |
< |
lock.lock(); |
1271 |
< |
try { |
1202 |
> |
synchronized (l.lock) { |
1203 |
|
rangeCheck(index); |
1204 |
|
checkForComodification(); |
1205 |
|
return l.get(index+offset); |
1275 |
– |
} finally { |
1276 |
– |
lock.unlock(); |
1206 |
|
} |
1207 |
|
} |
1208 |
|
|
1209 |
|
public int size() { |
1210 |
< |
final ReentrantLock lock = l.lock; |
1282 |
< |
lock.lock(); |
1283 |
< |
try { |
1210 |
> |
synchronized (l.lock) { |
1211 |
|
checkForComodification(); |
1212 |
|
return size; |
1286 |
– |
} finally { |
1287 |
– |
lock.unlock(); |
1213 |
|
} |
1214 |
|
} |
1215 |
|
|
1216 |
|
public void add(int index, E element) { |
1217 |
< |
final ReentrantLock lock = l.lock; |
1293 |
< |
lock.lock(); |
1294 |
< |
try { |
1217 |
> |
synchronized (l.lock) { |
1218 |
|
checkForComodification(); |
1219 |
|
if (index < 0 || index > size) |
1220 |
|
throw new IndexOutOfBoundsException(); |
1221 |
|
l.add(index+offset, element); |
1222 |
|
expectedArray = l.getArray(); |
1223 |
|
size++; |
1301 |
– |
} finally { |
1302 |
– |
lock.unlock(); |
1224 |
|
} |
1225 |
|
} |
1226 |
|
|
1227 |
|
public void clear() { |
1228 |
< |
final ReentrantLock lock = l.lock; |
1308 |
< |
lock.lock(); |
1309 |
< |
try { |
1228 |
> |
synchronized (l.lock) { |
1229 |
|
checkForComodification(); |
1230 |
|
l.removeRange(offset, offset+size); |
1231 |
|
expectedArray = l.getArray(); |
1232 |
|
size = 0; |
1314 |
– |
} finally { |
1315 |
– |
lock.unlock(); |
1233 |
|
} |
1234 |
|
} |
1235 |
|
|
1236 |
|
public E remove(int index) { |
1237 |
< |
final ReentrantLock lock = l.lock; |
1321 |
< |
lock.lock(); |
1322 |
< |
try { |
1237 |
> |
synchronized (l.lock) { |
1238 |
|
rangeCheck(index); |
1239 |
|
checkForComodification(); |
1240 |
|
E result = l.remove(index+offset); |
1241 |
|
expectedArray = l.getArray(); |
1242 |
|
size--; |
1243 |
|
return result; |
1329 |
– |
} finally { |
1330 |
– |
lock.unlock(); |
1244 |
|
} |
1245 |
|
} |
1246 |
|
|
1253 |
|
} |
1254 |
|
|
1255 |
|
public Iterator<E> iterator() { |
1256 |
< |
final ReentrantLock lock = l.lock; |
1344 |
< |
lock.lock(); |
1345 |
< |
try { |
1256 |
> |
synchronized (l.lock) { |
1257 |
|
checkForComodification(); |
1258 |
|
return new COWSubListIterator<E>(l, 0, offset, size); |
1348 |
– |
} finally { |
1349 |
– |
lock.unlock(); |
1259 |
|
} |
1260 |
|
} |
1261 |
|
|
1262 |
|
public ListIterator<E> listIterator(int index) { |
1263 |
< |
final ReentrantLock lock = l.lock; |
1355 |
< |
lock.lock(); |
1356 |
< |
try { |
1263 |
> |
synchronized (l.lock) { |
1264 |
|
checkForComodification(); |
1265 |
|
if (index < 0 || index > size) |
1266 |
|
throw new IndexOutOfBoundsException("Index: "+index+ |
1267 |
|
", Size: "+size); |
1268 |
|
return new COWSubListIterator<E>(l, index, offset, size); |
1362 |
– |
} finally { |
1363 |
– |
lock.unlock(); |
1269 |
|
} |
1270 |
|
} |
1271 |
|
|
1272 |
|
public List<E> subList(int fromIndex, int toIndex) { |
1273 |
< |
final ReentrantLock lock = l.lock; |
1369 |
< |
lock.lock(); |
1370 |
< |
try { |
1273 |
> |
synchronized (l.lock) { |
1274 |
|
checkForComodification(); |
1275 |
|
if (fromIndex < 0 || toIndex > size || fromIndex > toIndex) |
1276 |
|
throw new IndexOutOfBoundsException(); |
1277 |
|
return new COWSubList<E>(l, fromIndex + offset, |
1278 |
|
toIndex + offset); |
1376 |
– |
} finally { |
1377 |
– |
lock.unlock(); |
1279 |
|
} |
1280 |
|
} |
1281 |
|
|
1296 |
|
|
1297 |
|
public void replaceAll(UnaryOperator<E> operator) { |
1298 |
|
if (operator == null) throw new NullPointerException(); |
1299 |
< |
final ReentrantLock lock = l.lock; |
1399 |
< |
lock.lock(); |
1400 |
< |
try { |
1299 |
> |
synchronized (l.lock) { |
1300 |
|
int lo = offset; |
1301 |
|
int hi = offset + size; |
1302 |
|
Object[] elements = expectedArray; |
1311 |
|
newElements[i] = operator.apply(e); |
1312 |
|
} |
1313 |
|
l.setArray(expectedArray = newElements); |
1415 |
– |
} finally { |
1416 |
– |
lock.unlock(); |
1314 |
|
} |
1315 |
|
} |
1316 |
|
|
1317 |
|
public void sort(Comparator<? super E> c) { |
1318 |
< |
final ReentrantLock lock = l.lock; |
1422 |
< |
lock.lock(); |
1423 |
< |
try { |
1318 |
> |
synchronized (l.lock) { |
1319 |
|
int lo = offset; |
1320 |
|
int hi = offset + size; |
1321 |
|
Object[] elements = expectedArray; |
1328 |
|
@SuppressWarnings("unchecked") E[] es = (E[])newElements; |
1329 |
|
Arrays.sort(es, lo, hi, c); |
1330 |
|
l.setArray(expectedArray = newElements); |
1436 |
– |
} finally { |
1437 |
– |
lock.unlock(); |
1331 |
|
} |
1332 |
|
} |
1333 |
|
|
1334 |
|
public boolean removeAll(Collection<?> c) { |
1335 |
|
if (c == null) throw new NullPointerException(); |
1336 |
|
boolean removed = false; |
1337 |
< |
final ReentrantLock lock = l.lock; |
1445 |
< |
lock.lock(); |
1446 |
< |
try { |
1337 |
> |
synchronized (l.lock) { |
1338 |
|
int n = size; |
1339 |
|
if (n > 0) { |
1340 |
|
int lo = offset; |
1363 |
|
l.setArray(expectedArray = newElements); |
1364 |
|
} |
1365 |
|
} |
1475 |
– |
} finally { |
1476 |
– |
lock.unlock(); |
1366 |
|
} |
1367 |
|
return removed; |
1368 |
|
} |
1370 |
|
public boolean retainAll(Collection<?> c) { |
1371 |
|
if (c == null) throw new NullPointerException(); |
1372 |
|
boolean removed = false; |
1373 |
< |
final ReentrantLock lock = l.lock; |
1485 |
< |
lock.lock(); |
1486 |
< |
try { |
1373 |
> |
synchronized (l.lock) { |
1374 |
|
int n = size; |
1375 |
|
if (n > 0) { |
1376 |
|
int lo = offset; |
1399 |
|
l.setArray(expectedArray = newElements); |
1400 |
|
} |
1401 |
|
} |
1515 |
– |
} finally { |
1516 |
– |
lock.unlock(); |
1402 |
|
} |
1403 |
|
return removed; |
1404 |
|
} |
1406 |
|
public boolean removeIf(Predicate<? super E> filter) { |
1407 |
|
if (filter == null) throw new NullPointerException(); |
1408 |
|
boolean removed = false; |
1409 |
< |
final ReentrantLock lock = l.lock; |
1525 |
< |
lock.lock(); |
1526 |
< |
try { |
1409 |
> |
synchronized (l.lock) { |
1410 |
|
int n = size; |
1411 |
|
if (n > 0) { |
1412 |
|
int lo = offset; |
1435 |
|
l.setArray(expectedArray = newElements); |
1436 |
|
} |
1437 |
|
} |
1555 |
– |
} finally { |
1556 |
– |
lock.unlock(); |
1438 |
|
} |
1439 |
|
return removed; |
1440 |
|
} |
1509 |
|
|
1510 |
|
// Support for resetting lock while deserializing |
1511 |
|
private void resetLock() { |
1512 |
< |
U.putObjectVolatile(this, LOCK, new ReentrantLock()); |
1512 |
> |
U.putObjectVolatile(this, LOCK, new Object()); |
1513 |
|
} |
1514 |
|
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe(); |
1515 |
|
private static final long LOCK; |