見出し画像

[java入門] クラスAtomicLong解説

クラスAtomicLong

java.lang.Object
java.lang.Number
java.util.concurrent.atomic.Atomiclong
public class AtomicLong
extends Number
implements Serializable
原始的な更新が可能なlong値。
コンストラクタ
AtomicLong()
初期値0を使って、新しいAtomicLongを作成する。
AtomicLong(long initialValue)
指定された初期パラメータを使って、新しいAtomicLongを作成する

原始的な更新とは:

・例)AtomicIntegerクラスは「原始的な更新が可能なint値です」
・更新時に不可分操作を提供してくれるという意味。
integerクラスの相違点はここ。

マルチスレッドだと、ある変数を更新するときに同時に更新することが起こりうる。
・例えば変数に5を足す時を考える。この時コンピュータは
1変数の値を読む
2操作する
というステップで踏む必要があるが、A,Bの2スレッドが A1-B1-B1-B2になってしまうと最終結果が13ではなく8になってしまう。
この問題を解決。


java ExecutorService

・ExecutorServiceではスレッドプールが用意されるのでそこにタスクがディスパッチされることで処理が行われる。

Javaのタスクの状態

1created(作成された):サブミットされていない状態のタスクはcreatedステート。
2submitted(サブミットされた):submitまたは、executeメソッドでタスクをサブミットする
サブミットされても処理がかいししない場合は通常ブロッキングキューに入る。FIFOで処理される。
submitされた以降、メモリが割り当てられない等何らかの理由で処理がアボートする場合は、RejectedExecutionExceptionが発生する。
3 started(処理が開始した)
4 completed(完了した)
この状態は不可逆で、createdからcompletedへと順番に変わる。

スレッドプールとは?

スレッドプールは通常Webサーバーやデーターベースサーバーなど、複数のタスクを同時に素早く処理しなければならない状況で利用される。
スレッドプールとは複数のスレッドをあらかじめ作成して待機させておき、タスクがきたら待っているスレッドにタスクを割り当てて処理を開始させる仕組み
ゼロからこうした仕組みを実装するとなると、少々めんどくさいが、javaではExecutorServiceを使うことでスレッドプールを簡単に利用できる。
ExecutorServiceのサンプコード
・開始と終了時に動作しているスレッド名割り当てたタスクの番号を出力するだけにしている。
途中でランダムな値(ミリ秒)だけスリープしている。

これを次のようにしてExecutionServiceを使う。

```
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test {
public static void main(String[] args) {
Random random = new Random();
String threadName = Thread.currentThread().getName();
System.out.printf("+++ Begin %s +++\n", threadName);
//スレッドプールの作成
ExecutorService pool = Executors.newfixedThreadpool(3);
for (int i = 0; i < 10; i++) {
System.out.printf("* submit [%d]\n", i);
pool.submit(new SimpleTask(i, random.nextInt(1000)));
}
//シャットダウン
pool.shutdown();
System.out.printf("+++ End %s +++\n", threadName);
}
}
```
/* 解説
ここではスレッドプール内に3つのスレッドを作成して、そこに10個のタスクを投げている。
それぞれのタスクは最大1秒(1000ミリ秒)のランダムな時間だけ待機してから終了メッセージを出力して終了する。
出力結果から、スレッド名がpool-thread-1〜pool1-1-thread-3までの三つのスレッドが実行していたことがわかる。

java.util.current.Executors.newFixedThreadPoolというメソッドで、固定数のスレッドを持つスレッドプールを利用するExecutorServiceを取得する。
ExecutorServiceのsubmit()メソッドにタスクを渡すとタスクはsubmitted状態になる。
ここでは一度に10個のタスクの実行を要求しているがスレッドは3個だけ。
このためまず3個のタスクがstartedになり、残りの7個はsubmittedステートのままキューの中で待つ。
開始したタスクが終了したら、キューの中のタスクがスレッドに割り当てられてstartedの状態なる。

public class SimpleTask implements Runnable {
int number;
int wait;

public SimpleTask(int number, int wait) {
this.number = number;
this.wait = wait;
}

public void run() {
String threadName = Thread.currentThread().getName();
System.out.printf(
"+++ Begin [%d] %s +++\n",
number, threadName);
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.printf(
"+++ End [%d] on %s +++\n",
number, threadName);
}
}

この記事が気に入ったらサポートをしてみませんか?