Пишу свою реализацию потокобезопасного эррэй листа на CAS-блокировках (не спрашивайте зачем). Столкнулся с некоторым непонятным мне поведением в процессе записи элементов в лист. Код реализации методов записи:
public class CustomArrayList<T> implements List<T> {
private static final int DEFAULT_LENGTH = 16;
private volatile T[] array;
private AtomicInteger size = new AtomicInteger(0);
private volatile int rebuildSize = DEFAULT_LENGTH - 1;
public CustomArrayList() {
array = (T[]) new Object[DEFAULT_LENGTH];
}
public boolean add(T t) {
if (checkSize()) {
int tSize = size.getAndIncrement();
if (tSize >= rebuildSize) {
rebuild(tSize);
}
array[tSize] = t;
return true;
}
return false;
}
public boolean addAll(Collection<? extends T> c) {
if (checkSize()) {
int tSize;
do{
tSize = size.get();
}
while(!size.compareAndSet(tSize, tSize + c.size()));
if (tSize + c.size() >= rebuildSize) {
rebuild(tSize + c.size());
}
System.arraycopy((T[]) c.toArray(), 0, array, tSize, c.size());
return true;
}
return false;
}
private void rebuild(int newSize) {
synchronized (array) {
synchronized (size) {
if(newSize >= rebuildSize) {
long tempSize = size.get() * 2;
tempSize = tempSize > Integer.MAX_VALUE ? Integer.MAX_VALUE : tempSize;
T[] newArray = (T[]) new Object[(int) tempSize];
System.arraycopy(array, 0, newArray, 0, array.length);
array = newArray;
rebuildSize = array.length - 1;
}
}
}
}
private boolean checkSize() {
return size.get() < Integer.MAX_VALUE;
}
}
Код, который пишет в лист:
private static CountDownLatch cdl;
private static List<String> list;
private static final int ITER_COUNT = 6;
public static void main(String[] args) throws InterruptedException {
List<String> aList = Stream.of("A", "B",
"C").collect(Collectors.toList());
List<String> bList = Stream.of("D", "E",
"F").collect(Collectors.toList());
List<String> cList = Stream.of("G", "H",
"I").collect(Collectors.toList());
List<String> dList = Stream.of("J", "K",
"L").collect(Collectors.toList());
for (int j = 0; j < 1000; j++) {
list = new CustomArrayList<>(10);
cdl = new CountDownLatch(1);
new Thread(() -> {
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < ITER_COUNT; i++) {
if (i % 3 == 0 && i > 0) {
list.addAll(aList);
} else {
list.add(String.valueOf(i));
}
}
}).start();
new Thread(() -> {
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < ITER_COUNT; i++) {
if (i % 3 == 0 && i > 0) {
list.addAll(bList);
} else {
list.add(String.valueOf(i));
}
}
}).start();
new Thread(() -> {
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < ITER_COUNT; i++) {
if (i % 3 == 0 && i > 0) {
list.addAll(cList);
} else {
list.add(String.valueOf(i));
}
}
}).start();
new Thread(() -> {
try {
cdl.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < ITER_COUNT; i++) {
if (i % 3 == 0 && i > 0) {
list.addAll(dList);
} else {
list.add(String.valueOf(i));
}
}
}).start();
cdl.countDown();
Thread.sleep(50);
System.out.println(list);
}
}
Фрагмент вывода в консоль:
0,1,2,G,H,I,4,5,0,1,0,2,A,B,C,4,5,1,2,D,E,F,4,5,0,1,2,J,K,L,4,5 0,1,2,G,H,I,4,5,0,1,0,2,A,B,C,4,5,1,2,D,E,F,4,5,0,1,2,J,K,L,4,5 0,1,2,0,1,2,A,B,C,0,G,H,I,1,2,null,null,null,0,1,2,J,K,L,4,5,4,5,4,5,4,5 0,1,2,A,B,C,4,5,0,1,2,D,E,F,4,5,0,1,2,G,H,I,4,5,0,1,2,J,K,L,4,5
Мне не приходит в голову, почему в некоторых случаях в листе появляются значения null. При единичном добавлении элементов такое поведение тоже имеет место, только гораздо реже. Буду признателен, если кто нибудь подскажет, в чем дело. Спасибо.
System.arraycopy не является потокобезопасным. Он у Вас вызывается под гонкой. Вот ссылка на хороший пример, который демонстрирует проблемы System.arraycopy: http://www.programmersought.com/article/7454319322/
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Есть такая проблемкаВыводится какое-то кол-во яндекс карт, сейчас 3, в цикле
Есть задачка, в которой необходимо сравнить текущую дату с заданной в будущем с точностью до месяца включительно и определить разницу в количестве...
У Pinboard есть APIКогда я хочу обратится к нему из браузера мне выдает ошибку CORS
Планирую использовать slick slider в модальном окне (плагин Remodal)Посмотреть можно тут в разделе "Наши работы"