Java でコンカレント・リストを作る
並行性は、プログラムまたは関数を並行して実行するプロセスです。複数のスレッドが同じメソッドで動作する場合、時間の短縮とスループットの向上が可能になります。
Java は、List
操作の効率的な方法を可能にする CopyOnWriteArrayList
クラスを提供し、関数はスレッドセーフな方法で機能します。これは、2つ以上のスレッドがリストを操作しようとすると、指定されたクラスがスレッドセーフな方法で読み取り/書き込み
操作を許可することを意味します。内部的には、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 のドライバクラス
上記のプログラムでは、3つのクラスが定義されています。main
メソッドを持つ最初のものはドライバークラスであり、他のものは機能するためにあります。ConcurrentListOperations
クラスでは、一時リストは最初に 3つの整数で初期化されます。形成された temp_list
は、ArrayList
クラスの別のタイプである CopyOnWriteArrayList
コンストラクターに渡されます。
クラスは、上記で定義された値で配列を初期化します。これで、copyOnWriteArrayList
のインスタンスが以前に作成されたスレッドクラスに渡されます。このクラスは、リストをスレッドセーフにするだけです。したがって、リストインスタンスでの並列操作が可能になります。
Java のスレッドクラス
2つのスレッドクラスは、ReadThread
と WriteThread
です。クラスの実際の作業は、同じリストの読み取りと書き込みを同時に行うことです。WriteThread
クラスは、スレッドを宣言する 1つの方法である 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 ミリ秒スリープし、ライター出力は read
スレッドと比較して表示される回数が少なくなります。...
は、write
操作が行われていないため、スレッドが無限に実行され、同じ出力を出力することを意味します。write
プロセスが成功すると、read
スレッドは新しく追加された値を出力します。
出力:
Reader: 1 2 3
..
Writer done
Reader: 1 2 3 4
...
Writer done
Reader: 1 2 3 4 5
Rashmi is a professional Software Developer with hands on over varied tech stack. She has been working on Java, Springboot, Microservices, Typescript, MySQL, Graphql and more. She loves to spread knowledge via her writings. She is keen taking up new things and adopt in her career.
LinkedIn