English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
List 인터페이스의 크기가 변할 수 있는 배열의 구현입니다. 모든 선택적인 목록 작업을 구현하고, null을 포함한 모든 요소를 허용합니다. List 인터페이스를 구현 외에도, 이 클래스는 목록을 저장하는 내부 배열의 크기를 조작하는 몇 가지 메서드를 제공합니다. (이 클래스는 Vector 클래스와 유사하지만, 이 클래스는 동기화되어 있지 않습니다.) size, isEmpty, get, set, iterator 및 listIterator 작업은 고정된 시간으로 실행됩니다. add 작업은 분산된 고정된 시간으로 실행되며, 즉 n 개의 요소를 추가하는 데는 O(n) 시간이 필요합니다. 다른 모든 작업은 선형 시간으로 실행됩니다. LinkedList 구현에 사용되는 상수 계수와 비교하여, 이 구현의 상수 계수가 낮습니다. 각 ArrayList 인스턴스는 용량이 있습니다. 이 용량은 목록 요소를 저장하는 배열의 크기입니다. 이는 항상 목록의 크기보다 크거나 같습니다. ArrayList에 요소를 추가함에 따라 용량도 자동으로 증가합니다. 증가 전략의 세부 사항은 명시되지 않았으며, 이는 단순히 요소를 추가하는 것만으로도 분산된 고정된 시간 비용이 발생하기 때문입니다. 많은 요소를 추가하기 전에, 애플리케이션은 ArrayList 인스턴스의 용량을 증가시키는 ensureCapacity 작업을 사용할 수 있습니다. 이는 재할당의 횟수를 줄일 수 있습니다.
이 구현은 동기화되어 있지 않습니다.
여러 스레드가 동시에 ArrayList 인스턴스에 접근하면, 그 중 적어도 하나의 스레드가 구조적으로 목록을 수정하면, 반드시 외부 동기화를 유지해야 합니다. (구조적인 수정은 하나나 여러 개의 요소를 추가하거나 제거하는 작업이나, 내부 배열의 크기를 명시적으로 조정하는 것을 의미합니다. 요소의 값을 설정하는 것만은 구조적인 수정이 아닙니다.) 이는 일반적으로 목록을 자연스럽게 둘러싸는 객체에 동기화 작업을 통해 완료됩니다. 그러한 객체가 존재하지 않으면, Collections.synchronizedList 메서드를 사용하여 목록을 '포장'해야 합니다. 이는 생성 시에 완료하는 것이 좋으며, 목록에 대한 갑작스러운 비동기화 접근을 방지하기 위해서입니다:
Listlist=Collections.synchronizedList(newArrayList(...));
此类iterator和listIterator方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的remove或add方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。
请注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测bug。
如上所示,现在建立一个list集合,一个线程对集合进行写入操作,一个线程进行删除操作
import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Random; public class MyArrayList { /** * 리스트를 생성하고, 하나의 스레드가 쓰기하고 하나의 스레드가 읽기하도록 합니다. iterator와 listIterator 메서드는 빠르게 실패하는 반복자입니다. */ public void readWrite() { List<Integer> nums = new ArrayList<Integer>(); List<Integer> synNums = Collections.synchronizedList(nums); //쓰기 스레드를 시작합니다 new WriteListThread(synNums).start(); //삭제 스레드를 시작합니다 new DeleteListThread(synNums).start(); } public static void main(String[] args) { new MyArrayList().readWrite(); } } class WriteListThread extends Thread { private List<Integer> nums; public WriteListThread(List<Integer> nums) { super(“WriteListThread”); this.nums = nums; } // 1 public void run() { while (true) { nums.add(new Random().nextint(1000)); System.out.println(Thread.currentThread().getName()); } } } class DeleteListThread extends Thread { private List<Integer> nums; public DeleteListThread(List<Integer> nums) { super(“DeleteListThread”); this.nums = nums; } // 첫 번째 요소를 제거합니다 public void run() { while (true) { try{ System.out.println(Thread.currentThread().getName()+:"+nums.remove(0)); } catch(Exception e){ continue ; } } } }
通过List<Integer>synNums=Collections.synchronizedList(nums);就能对原子操作进行同步了,但是官方api示例为什么要自己手动添加同步呢?
List list = Collections.synchronizedList(new ArrayList()); synchronized(list) { Iterator i = list.iterator(); // 必须是同步块中 while (i.hasNext()) foo(i.next()); }
查看Collections.synchronizedList的源代码
SynchronizedCollection(Collection<E> c) { if (c==null) throw new NullPointerException(); this.c = c; mutex = this; }
import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Random; public class MyArrayList { /** * 리스트를 생성하고, 하나의 스레드가 쓰기하고 하나의 스레드가 읽기하도록 합니다. iterator와 listIterator 메서드는 빠르게 실패하는 반복자입니다. */ public void readWrite() { List<Integer> nums = new ArrayList<Integer>(); List<Integer> synNums = Collections.synchronizedList(nums); //쓰기 스레드를 시작합니다 new WriteListThread(synNums).start(); //삭제 스레드를 시작합니다 new DeleteListThread(synNums).start(); } public static void main(String[] args) { new MyArrayList().readWrite(); } } class WriteListThread extends Thread { private List<Integer> nums; public WriteListThread(List<Integer> nums) { super("WriteListThread"); this.nums = nums; } // 1 public void run() { while (true) { nums.add(new Random().nextint(1000)); System.out.println(Thread.currentThread().getName()); } } } class DeleteListThread extends Thread { private List<Integer> nums; public DeleteListThread(List<Integer> nums) { super("DeleteListThread"); this.nums = nums; } // 첫 번째 요소를 제거합니다 public void run() { while (true) { try{ System.out.println(Thread.currentThread().getName()+":"+nums.remove(0)); } catch(Exception e){ continue ; } } } }
집합의 동기화 작업에 대해 Collections의 동기화 패키지 클래스를 사용하면 추가로 원자적 작업을 동기화해야 합니다.
그림에서 보듯, 하나의 스레드를 추가하여 셋을 읽습니다.
class ReadListThread extends Thread { private List<Integer> nums; public ReadListThread(List<Integer> nums) {}} super(“ReadListThread”); this.nums = nums; } // 요소를 지속적으로 읽어 들이며, 원자적 작업이 아닌 경우에는 수동으로 락을 추가해야 합니다 public void run() { while (true) { //대기하고, 다른 스레드에 락을 넘겨줍니다 try { Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); } synchronized (nums) { if (nums.size() > 100) { Iterator<Integer> iter = nums.iterator(); while (iter.hasNext()) { System.out.println(Thread.currentThread().getName() + :" + iter.next()); ; } } else{ try { nums.wait(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
결론
이것이 본 문서에서 java 컬렉션 프레임워크 스레드 동기화 코드의 전체 설명입니다. 많은 도움이 되길 바랍니다. 관심이 있는 분들은 본 사이트의 다른 관련 주제를 참고해 주시고, 부족한 점이 있으면 의견을 남겨 주시기 바랍니다. 친구 여러분의 본 사이트에 대한 지지에 감사드립니다!
고지: 본 문서의 내용은 인터넷에서 가져왔으며, 저작권은 원저자에게 있으며, 인터넷 사용자가 자발적으로 기여하고 업로드한 내용으로, 본 사이트는 소유권을 가지지 않으며, 인공 편집을 하지 않았으며, 관련 법적 책임도 부담하지 않습니다. 저작권 문제가 있는 내용을 발견하시면, notice#w로 이메일을 보내 주시기 바랍니다.3codebox.com에 (메일 작성 시, #을 @으로 변경하여) 신고를 해 주시고, 관련 증거를 제공해 주시면, 해당 내용이 확인되면 즉시 해당 내용을 삭제하겠습니다.