1,Copy-On-Write
что это?
Сначала позвольте мне рассказать вам, что такоеCopy-On-Write
, как следует из названия, в компьютере, когда вы хотите модифицировать кусок памяти, мы не делаем это в исходном блоке памяти写
операцию, но скопируйте копию памяти и выполните ее в новой памяти写
действовать,写
После этого наведите указатель на исходную память на новую память, и исходную память можно переработать!
Братья в Интернете сказали, что это своего рода программирование, используемое в программировании优化策略
, это延时懒惰策略
. Говорят, что оптимизация оптимизируется, так какие проблемы оптимизируются?
Сначала дайте вам код:
public class IteratorTest {
private static List<String> list = new ArrayList<>();
public static void main(String[] args) {
list.add("1");
list.add("2");
list.add("3");
Iterator<String> iter = list.iterator();
//我当前正在迭代集合(这里模拟并发中读取某一list的场景)
while (iter.hasNext()) {
System.err.println(iter.next());
}
System.err.println(Arrays.toString(list.toArray()));
}
}
Приведенный выше фрагмент программы хорош при выполнении в одном потоке, но в многопоточном окружении это может быть ГГ! Зачем? Поскольку в многопоточной среде другим потокам не разрешено добавлять элементы в этот список коллекций при итерации.Посмотрите на следующий код, вы обнаружите, что выбросjava.util.ConcurrentModificationException
исключение.
public class IteratorTest {
private static List<String> list = new ArrayList<>();
public static void main(String[] args) {
list.add("1");
list.add("2");
list.add("3");
Iterator<String> iter = list.iterator();
// 存放10个线程的线程池
ExecutorService service = Executors.newFixedThreadPool(10);
// 执行10个任务(我当前正在迭代集合(这里模拟并发中读取某一list的场景))
for (int i = 0; i < 10; i++) {
service.execute(new Runnable() {
@Override
public void run() {
while (iter.hasNext()) {
System.err.println(iter.next());
}
}
});
}
// 执行10个任务
for (int i = 0; i < 10; i++) {
service.execute(new Runnable() {
@Override
public void run() {
list.add("121");// 添加数据
}
});
}
System.err.println(Arrays.toString(list.toArray()));
}
}
- 1. здесь
迭代
Указывает, что в настоящее время я читаю некоторые集合
данные в读
действовать; - 2. Поток имитирует, что текущая программа находится в многопоточной среде, а другие потоки изменяют данные.
Какая проблема раскрыта здесь?
- 1. Многопоточность повлияет на итеративный сбор и повлияет на операцию чтения
решать:
- 1,
CopyOnWriteArrayList
Избегайте проблемы многопоточной работы Небезопасность списка потоков
2,CopyOnWriteArrayList
вводить
Начиная с JDK1.5, в параллельном пакете Java предусмотрено два варианта использования.CopyOnWrite
механизм для реализации параллельных контейнеров, ониCopyOnWriteArrayList
иCopyOnWriteArraySet
.CopyOnWrite
Контейнеры очень полезны и могут использоваться во многих сценариях параллелизма.
CopyOnWriteArrayList
принцип:
上面已经讲了,就是在写的时候不对原集合进行修改,而是重新复制一份,修改完之后,再移动指针
Так вы можете спросить? Даже если исходная коллекция будет скопирована, не вызовет ли это конфликтов записи в многопоточной среде? Да, но вы можете этого еще не знатьCopyOnWriteArrayList
Добавьте детали реализации удаления элементов вadd()方法
3.CopyOnWriteArrayList
Простая интерпретация исходного кода
add()
Исходный код метода:
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
final ReentrantLock lock = this.lock;//重入锁
lock.lock();//加锁啦
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);//拷贝新数组
newElements[len] = e;
setArray(newElements);//将引用指向新数组 1
return true;
} finally {
lock.unlock();//解锁啦
}
}
Внезапно понял, проба, оказываетсяadd()
При добавлении коллекции добавляется блокировка, чтобы обеспечить синхронизацию и избежать копирования N копий при многопоточной записи. (想想,你在遍历一个10个元素的集合,每遍历一次有1人调用add方法,你说当你遍历10次,这add方法是不是得被调用10次呢?是不是得copy出10分新集合呢?万一这个集合非常大呢?
)
Так? вы все еще спрашиваете?CopyOnWriteArrayList
Как решить проблему потокобезопасности? Ответ-写时复制,加锁
Еще спрашивать? Так бывает ли такая ситуация, когда поток только что закончил вызыватьadd()
метод, который только что выполняется для вышеуказанного1
Код в , то есть просто указать ссылку на массив сердца, и есть ли поток, обходящий его в это время? Сообщит об ошибке? (答案是不会的,因为你正在遍历的集合是旧的,这就有点难受啦,哈哈~
)
Когда вы помещаете приведенный выше кодArrayList
изменить наCopyOnWriteArrayList
, выполнение не сообщит об ошибке!
public class IteratorTest {
private static CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
public static void main(String[] args) {
list.add("1");
list.add("2");
list.add("3");
Iterator<String> iter = list.iterator();
// 存放10个线程的线程池
ExecutorService service = Executors.newFixedThreadPool(10);
// 执行10个任务(我当前正在迭代集合(这里模拟并发中读取某一list的场景))
for (int i = 0; i < 10; i++) {
service.execute(new Runnable() {
@Override
public void run() {
while (iter.hasNext()) {
System.err.println(iter.next());
}
}
});
service.execute(new Runnable() {
@Override
public void run() {
list.add("121");// 添加数据
}
});
}
// 执行10个任务
for (int i = 0; i < 10; i++) {
service.execute(new Runnable() {
@Override
public void run() {
list.add("121");// 添加数据
}
});
service.execute(new Runnable() {
@Override
public void run() {
while (iter.hasNext()) {
System.err.println(iter.next());
}
}
});
}
System.err.println(Arrays.toString(list.toArray()));
}
}
4.CopyOnWriteArrayList
Преимущества и недостатки
недостаток:
- 1. Потребление памяти (репликация коллекции)
- 2. Производительность в реальном времени невысокая
преимущество:
- 1. Согласованность данных полная, почему? Из-за блокировки параллельные данные не будут хаотичными
- 2, решено
像ArrayList
,Vector
Такого рода задача многопоточной итерации обхода коллекции, помните,Vector
Хотя потокобезопасный, он просто добавляетsynchronized
Ключевое слово, итерационная задача вообще не решена!
5.CopyOnWriteArrayList
сцены, которые будут использоваться
- 1. Больше читать и меньше писать (белый список, черный список, сценарии доступа и обновления товарных категорий), почему? Потому что новая коллекция копируется при записи
- 2. Коллекция не большая, почему? Потому что новая коллекция копируется при записи
- Требования к реальному времени не высоки, почему, ведь есть возможность читать старые данные коллекции
Справочная статья:Как безопасно перемещаться по списку: Vector, CopyOnWriteArrayList
Редактор старший, стажер, и его знания все еще поверхностны Добро пожаловать, чтобы комментировать и обмениваться, учиться вместе и добиваться прогресса вместе!