HOWTO · Java
在 Java 中建立併發列表
本文介紹如何在 Java 中製作併發列表。
併發是在並行執行中執行程式或函式的過程。當多個執行緒在同一個方法上工作時,它可以減少時間並增加吞吐量。
Java 提供了 CopyOnWriteArrayList 類,它允許一種有效的 List 操作方式,並且這些函式以執行緒安全的方式工作。這意味著當兩個或多個執行緒嘗試操作列表時,給定的類允許以執行緒安全的方式進行讀寫操作。在內部,當修改列表介面的方法(例如 add 或 remove 函式)時,CopyOnWriteArrayList 的內容會被複制到新的內部副本中。此功能使其成為執行緒安全的並允許並行處理。
CopyOnWriteArrayList 類存在於 java.util.concurrent 包中。下面是一個程式碼塊示例,演示了對給定類的操作。
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class ConcurrentListOperations {
public static void main(String[] args) {
List<Integer> temp_list = Arrays.asList(1, 2, 3);
List<Integer> list = new CopyOnWriteArrayList<>(temp_list);
new WriteThread("Writer", list).start();
new ReadThread("Reader", list).start();
}
}
class WriteThread extends Thread {
private final List<Integer> list;
public WriteThread(String name, List<Integer> list) {
this.list = list;
super.setName(name);
}
public void run() {
int count = 4;
int counter = 0;
do {
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
list.add(count++);
System.out.println(super.getName() + " done");
counter++;
} while (counter != 5);
}
}
class ReadThread extends Thread {
private final List<Integer> list;
public ReadThread(String name, List<Integer> list) {
this.list = list;
super.setName(name);
}
public void run() {
while (true) {
StringBuilder output = new StringBuilder("\n" + super.getName() + ":");
for (Integer nextVal : list) {
output.append(" ").append(nextVal);
}
System.out.println(output);
}
}
}
Java 中的驅動類
在上面的程式中,定義了三個類。帶有 main 方法的第一個是驅動類,其他的用於執行。在 ConcurrentListOperations 類中,臨時列表最初使用三個整數進行初始化。形成的 temp_list 被傳遞到 CopyOnWriteArrayList 建構函式,這是另一種型別的 ArrayList 類。
該類使用上面定義的值初始化陣列。現在,copyOnWriteArrayList 的例項被傳遞給之前建立的執行緒類。這個類只會使列表執行緒安全;因此,允許對列表例項進行並行操作。
Java 中的執行緒類
兩個執行緒類是 ReadThread 和 WriteThread。該類的實際工作是同時讀寫同一個列表。WriteThread 類擴充套件了 Thread 類,這是宣告執行緒的一種方式。它有一個公共建構函式,用於將接收到的列表例項分配給區域性變數並初始化執行緒名稱。
執行緒的實際業務邏輯存在於它們的 run 方法中。要啟動一個執行緒,在新建立的執行緒類例項上呼叫 start 方法。
在 Java 中使用 run 方法
在 WriteThread 類的 run 方法中,在迴圈條件中初始化一個計數器以跟蹤 run 方法中 write 類的迭代。do-while 迴圈用於跟蹤迭代執行的次數。
在條件塊中,呼叫 Thread 類的 sleep 方法使執行緒在定義的時間內休眠。該函式使並行執行執行緒休眠一定的毫秒數。如果傳遞的毫秒數為負,則丟擲 IllegalArgumentException,如果任何執行緒被中斷,則丟擲 InterruptedException。
add 方法用於通過併發執行緒在列表中新增元素。如果列表例項不允許該操作,它會丟擲 UnsupportedOperationException。另一方面,如果指定元素的類與列表的型別不同,它會丟擲 ClassCastException。如果指定值為 null,則丟擲 NullPointerException,如果此元素的某些屬性阻止新增元素,則丟擲 IllegalArgumentException。
同樣,在 ReadThread 類的 run 方法中,定義了一個建構函式;它初始化名稱和列表。run 方法具有實際的 read 邏輯。StringBuilder 類用於在輸出中進行操作。append 方法將在寫入執行緒類中找到的輸出與現有的輸出相附加。
因此,read 和 write 操作同時發生並以上述格式列印在控制檯中。寫入執行緒休眠大約 5000 毫秒,與讀取執行緒相比,寫入器輸出顯示的次數更少。... 表示執行緒無休止地執行並列印相同的輸出,因為沒有進行 write 操作。一旦寫入過程成功,讀取執行緒現在會列印新新增的值。
輸出:
Reader: 1 2 3
..
Writer done
Reader: 1 2 3 4
...
Writer done
Reader: 1 2 3 4 5