Java CopyOnWriteArrayList Methods - Java 147

Java CopyOnWriteArrayList Methods – Java 147

Java CopyOnWriteArrayList Methods

在不需要明確同步時,使用執行緒安全的方式遍歷集合,當任何修改方法,例如: add 或 remove 時,全部內容都會複製到新的內部副本中,即使發生並發修改,也可以安全的方式遍歷集合,調用 iterator 方法時,會傳回一個不可變快照備份的遍歷器, CopyOnWriteArrayList Java Methods 介紹常見的 add 、 get 、 set 、 clear 、 size 等方法,了解陣列列表的不同操作和方法,本篇增加了範例,並透過單元測試來驗證產出結果。

檔案目錄

./
   +- src
       +- test
       |   +- org
       |       +- ruoxue
       |           +- java_147
       |               +- list
       |                   +- copyonwritearraylist
       |                       +- CopyOnWriteArrayListMethodsTest.java   

單元測試

CopyOnWriteArrayList Methods Java 提供新增、取得、修改、刪除等操作列表中的元素。

readWriteThrowException

建立一個 ArrayList ,增加三個元素,多執行緒進行讀取元素時,同時寫入元素,會拋出例外。

	@Test
	public void readWriteThrowException() {
		try {
			int poolSize = 3;
			ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
			List<String> list = new ArrayList<>();
			list.add("Apple");
			list.add("Banana");
			list.add("Cherry");
			for (int i = 0; i < poolSize; i++) {
				executorService.execute(() -> {
					Iterator<String> it = list.iterator();
					while (it.hasNext()) {
						System.out.println(String.format("[%d] %s", Thread.currentThread().getId(), it.next()));
					}
				});
			}

			for (int i = 0; i < poolSize; i++) {
				executorService.execute(() -> {
					list.add("Grape");
				});
			}
			Thread.sleep(2_000L);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
[12] Cherry
[13] Cherry
[11] Cherry
Exception in thread "pool-1-thread-1" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
	at java.util.ArrayList$Itr.next(ArrayList.java:859)
	at org.ruoxue.java_147.list.copyonwritearraylist.CopyOnWriteArrayListMethodsTest.lambda$0(CopyOnWriteArrayListMethodsTest.java:33)

readWrite

CopyOnWriteArrayList Methods Java 建立一個 CopyOnWriteArrayList ,增加三個元素,多執行緒進行讀寫元素時,能夠安全地遍歷集合。

	@Test
	public void readWrite() {
		try {
			int poolSize = 3;
			ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
			List<String> list = new CopyOnWriteArrayList<>();
			list.add("Apple");
			list.add("Banana");
			list.add("Cherry");
			for (int i = 0; i < poolSize; i++) {
				executorService.execute(() -> {
					Iterator<String> it = list.iterator();
					while (it.hasNext()) {
						System.out.println(String.format("[%d] %s", Thread.currentThread().getId(), it.next()));
					}
				});
			}

			for (int i = 0; i < poolSize; i++) {
				executorService.execute(() -> {
					list.add("Grape");
				});
			}
			Thread.sleep(2_000L);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
[13] Apple
[11] Apple
[13] Banana
[12] Apple
[11] Banana
[13] Cherry
[11] Cherry
[12] Banana
[12] Cherry

add

CopyOnWriteArrayList Methods Java 建立一個 CopyOnWriteArrayList ,增加三個元素。

	@Test
	public void add() {
		int expectedSize = 3;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}
[Apple, Banana, Cherry]

addByIndex

CopyOnWriteArrayList Methods Java 建立一個 CopyOnWriteArrayList ,內有三個元素,指定位置增加第四個元素。

	@Test
	public void addByIndex() {
		int expectedSize = 4;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		list.add(2, "Grape");
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}
[Apple, Banana, Grape, Cherry]

addAll

CopyOnWriteArrayList Methods in Java 建立兩個 CopyOnWriteArrayList ,內各有三個元素,合併成為一個 List 。

	@Test
	public void addAll() {
		int expectedSize = 6;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");

		List<String> list2 = new CopyOnWriteArrayList<>();
		list2.add("Grape");
		list2.add("Lemon");
		list2.add("Mango");

		list.addAll(list2);
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}
[Apple, Banana, Cherry, Grape, Lemon, Mango]

get

CopyOnWriteArrayList Methods in Java 建立一個 CopyOnWriteArrayList ,內有三個元素,取得指定位置元素。

	@Test
	public void get() {
		String expected = "Banana";
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		String value = list.get(1);
		System.out.println(value);
		assertEquals(expected, value);
	}
Banana

set

CopyOnWriteArrayList Methods in Java 建立一個 CopyOnWriteArrayList ,內有三個元素,修改指定位置元素。

	@Test
	public void set() {
		String expected = "Grape";
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		System.out.println(list);

		list.set(0, "Grape");
		System.out.println(list);
		assertEquals(expected, list.get(0));
	}
[Apple, Banana, Cherry]
[Grape, Banana, Cherry]

remove

CopyOnWriteArrayList Functions in Java 建立一個 CopyOnWriteArrayList ,內有三個元素,刪除指定位置元素。

	@Test
	public void remove() {
		int expectedSize = 2;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		list.remove(0);
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}
[Banana, Cherry]

removeAll

CopyOnWriteArrayList Functions in Java 建立一個 CopyOnWriteArrayList ,內有三個元素,刪除來自另一個 List 中的元素。

	@Test
	public void removeAll() {
		int expectedSize = 1;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");

		List<String> list2 = new CopyOnWriteArrayList<>();
		list2.add("Apple");
		list2.add("Banana");
		list2.add("Mango");
		list.removeAll(list2);
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}
[Cherry]

clear

CopyOnWriteArrayList Functions in Java 建立一個 CopyOnWriteArrayList ,內有三個元素,刪除所有元素。

	@Test
	public void clear() {
		int expectedSize = 0;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		list.clear();
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}
[]	

size

建立一個 CopyOnWriteArrayList ,內有三個元素,取得集合大小。

	@Test
	public void size() {
		int expectedSize = 3;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		System.out.println(list.size());
		assertEquals(expectedSize, list.size());
	}
3

isEmpty

建立一個 CopyOnWriteArrayList ,檢查是否為空 List 。

	@Test
	public void isEmpty() {
		List<String> list = new CopyOnWriteArrayList<>();
		System.out.println(list.isEmpty());
		assertTrue(list.isEmpty());
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		System.out.println(list.isEmpty());
		assertFalse(list.isEmpty());
	}
true
false

CopyOnWriteArrayListMethodsTest.java

CopyOnWriteArrayList Methods in Java 新增單元測試,驗證 CopyOnWriteArrayList Functions in Java 是否符合預期。

package org.ruoxue.java_147.list.copyonwritearraylist;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.Test;

public class CopyOnWriteArrayListMethodsTest {

	@Test
	public void readWriteThrowException() {
		try {
			int poolSize = 3;
			ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
			List<String> list = new ArrayList<>();
			list.add("Apple");
			list.add("Banana");
			list.add("Cherry");
			for (int i = 0; i < poolSize; i++) {
				executorService.execute(() -> {
					Iterator<String> it = list.iterator();
					while (it.hasNext()) {
						System.out.println(String.format("[%d] %s", Thread.currentThread().getId(), it.next()));
					}
				});
			}

			for (int i = 0; i < poolSize; i++) {
				executorService.execute(() -> {
					list.add("Grape");
				});
			}
			Thread.sleep(2_000L);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	@Test
	public void readWrite() {
		try {
			int poolSize = 3;
			ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
			List<String> list = new CopyOnWriteArrayList<>();
			list.add("Apple");
			list.add("Banana");
			list.add("Cherry");
			for (int i = 0; i < poolSize; i++) {
				executorService.execute(() -> {
					Iterator<String> it = list.iterator();
					while (it.hasNext()) {
						System.out.println(String.format("[%d] %s", Thread.currentThread().getId(), it.next()));
					}
				});
			}

			for (int i = 0; i < poolSize; i++) {
				executorService.execute(() -> {
					list.add("Grape");
				});
			}
			Thread.sleep(2_000L);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	@Test
	public void add() {
		int expectedSize = 3;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}

	@Test
	public void addByIndex() {
		int expectedSize = 4;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		list.add(2, "Grape");
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}

	@Test
	public void addAll() {
		int expectedSize = 6;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");

		List<String> list2 = new CopyOnWriteArrayList<>();
		list2.add("Grape");
		list2.add("Lemon");
		list2.add("Mango");

		list.addAll(list2);
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}

	@Test
	public void get() {
		String expected = "Banana";
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		String value = list.get(1);
		System.out.println(value);
		assertEquals(expected, value);
	}

	@Test
	public void set() {
		String expected = "Grape";
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		System.out.println(list);

		list.set(0, "Grape");
		System.out.println(list);
		assertEquals(expected, list.get(0));
	}

	@Test
	public void remove() {
		int expectedSize = 2;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		list.remove(0);
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}

	@Test
	public void removeAll() {
		int expectedSize = 1;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");

		List<String> list2 = new CopyOnWriteArrayList<>();
		list2.add("Apple");
		list2.add("Banana");
		list2.add("Mango");
		list.removeAll(list2);
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}

	@Test
	public void clear() {
		int expectedSize = 0;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		list.clear();
		System.out.println(list);
		assertEquals(expectedSize, list.size());
	}

	@Test
	public void size() {
		int expectedSize = 3;
		List<String> list = new CopyOnWriteArrayList<>();
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		System.out.println(list.size());
		assertEquals(expectedSize, list.size());
	}

	@Test
	public void isEmpty() {
		List<String> list = new CopyOnWriteArrayList<>();
		System.out.println(list.isEmpty());
		assertTrue(list.isEmpty());
		list.add("Apple");
		list.add("Banana");
		list.add("Cherry");
		System.out.println(list.isEmpty());
		assertFalse(list.isEmpty());
	}
}

心得分享

CopyOnWriteArrayList Functions in Java 不在原有記憶體區塊中進行寫入操作,而是將記憶體拷貝一份,在新的記憶體中進行寫操作,寫完之後,利用加鎖保證同步,將指針指向新的記憶體,原來的記憶體就可以被回收掉,這是一種用於程式設計中的最佳化策略,是一種延時懶惰策略,提供了幾種 CopyOnWriteArrayList 常見方法的操作範例,在應用上相當廣泛,熟悉 CopyOnWriteArrayList Methods in Java 這些方法的操作,可以快速撰寫程式,降低錯誤率。

發佈留言