Java : Executors - API使用例
Executors (Java SE 19 & JDK 19) の使用例まとめです。
だいたいのメソッドを網羅済みです。
API仕様のおともにどうぞ。
概要
Executors は、ExecutorServiceのインスタンスを作成するユーティリティクラスです。
try (final var executorService = Executors.newSingleThreadExecutor()) {
final Runnable task = () -> {
System.out.println(" task start");
System.out.println(" thread id = " + Thread.currentThread().threadId());
};
System.out.println("-- submit start --");
System.out.println("thread id = " + Thread.currentThread().threadId());
executorService.submit(task);
System.out.println("-- submit end --");
}
System.out.println("-- terminated --");
// 結果
// ↓
//-- submit start --
//thread id = 1
//-- submit end --
// task start
// thread id = 33
//-- terminated --
作成する ExecutorService は大きく分けて5つの種類があります。
メソッド | 簡単な説明 | 使用ケース |
---|---|---|
newSingleThreadExecutor | 1つのスレッドを持つ ExecutorService を作成します。 タスクはその1つのスレッドでのみ実行されます。 タスクAを実行中にタスクBが追加された場合、タスクBはキューに入りタスクAの実行完了を待ちます。 タスクAの実行が完了したら、キューからタスクBが取り出され、スレッド上でタスクBが実行されます。 |
明確に1つのスレッドのみ使いたい、というケースで使います。 例えば、1つのスレッドに制限することにより synchronized を省きたいときです。 |
newWorkStealingPool | プロセッサ数に応じたスレッド数を持つ ExecutorService を作成します。 Java 8で新しく追加されました。 いろいろと最適化されていて、パフォーマンスが良いようです。 |
比較的短時間で済むタスクを、複数スレッドで大量に処理したいときに使います。 後述しますが、Future.cancel(true) によるスレッドの割込みは効果がないのでご注意ください。 |
newScheduledThreadPool | ScheduledExecutorService を作成します。 ScheduledExecutorService はタスクをスケジューリングできます。 例えば、1分後にタスクを実行、というような使い方ができます。 |
タスクのスケジューリングが必要となるケースで使います。 |
newFixedThreadPool | 指定した固定数のスレッドを持つ ExecutorService を作成します。 スレッドは ExecutorService.shutdown するまで残り続けます。 |
ストレージへのアクセスやネットワーク通信など、比較的長い時間スレッドを占有するようなタスクに向いています。 |
newCachedThreadPool | 複数のスレッドを持つ ExecutorService を作成します。 スレッドは60秒間使われないと、キャッシュから削除され解放されます。 ここが newFixedThreadPool と違う点です。 タスクが追加されスレッドが必要になると、再度スレッドが生成されます。 |
API仕様には、"通常、これらのプールは、短期の非同期タスクを多数実行するプログラムのパフォーマンスを改善します" とあります。 プールを使用していない時間はスレッドが解放されているので、リソース的には優しいです。 その代わり、スレッドが必要になったときに、スレッドの再作成が必要となるので、その分の処理がかかります。 |
複数スレッドによる並列処理が必要な場合は、まずは新しいAPIである newWorkStealingPool を使うことを検討してみましょう。
他の API に比べてパフォーマンスが良いようです。
ただし、newWorkStealingPool には注意点があります。それは、Future.cancel(true) によるスレッドの割込みが効かないことです。
API仕様には明記されていないのですが、どうも 内部では ForkJoinPool を使っており、その Future は ForkJoinTask になります。
ForkJoinTask.cancel のパラメータ( mayInterruptIfRunning ) の説明に、デフォルトの実装では効果なし、と説明があります。
外部サイトで英語ですが、以下の記事も参考にお願いします。
もし、Future.cancel(true) によるスレッド割込みを行いたいケースでは、代わりに newFixedThreadPool を使うことも検討してみましょう。
日本語訳の注意点
API仕様の日本語訳に、"共有アンバウンド形式のキューなしで動作"という表現があります。
これは、正確には "サイズ制限のない共有キューを使って動作" という意味になります。ご注意ください。
メソッド
static Callable<Object> callable (Runnable task)
final var callable = Executors.callable(() -> System.out.println("abcd"));
final var ret = callable.call(); // abcd
System.out.println(ret); // null
static <T> Callable<T> callable (Runnable task, T result)
final var callable = Executors.callable(() -> System.out.println("abcd"), "XYZ");
final var ret = callable.call(); // abcd
System.out.println(ret); // XYZ
static Callable<Object> callable (PrivilegedAction<?> action)
final var privilegedAction = new PrivilegedAction<>() {
@Override
public Object run() {
System.out.println("abcd");
return "XYZ";
}
};
final var callable = Executors.callable(privilegedAction);
final var ret = callable.call(); // abcd
System.out.println(ret); // XYZ
static Callable<Object> callable (PrivilegedExceptionAction<?> action)
final var privilegedExceptionAction = new PrivilegedExceptionAction<>() {
@Override
public Object run() {
System.out.println("abcd");
return "XYZ";
}
};
final var callable = Executors.callable(privilegedExceptionAction);
final var ret = callable.call(); // abcd
System.out.println(ret); // XYZ
static ThreadFactory defaultThreadFactory ()
final var threadFactory = Executors.defaultThreadFactory();
final var thread = threadFactory.newThread(() -> {
System.out.println("Run!");
});
System.out.println("thread id : " + thread.threadId());
System.out.println("thread name : " + thread.getName());
System.out.println("thread priority : " + thread.getPriority());
System.out.println("-- start --");
thread.start();
thread.join();
System.out.println("-- join --");
// 結果
// ↓
//thread id : 33
//thread name : pool-1-thread-1
//thread priority : 5
//-- start --
//Run!
//-- join --
static ExecutorService newCachedThreadPool ()
class Task implements Runnable {
private final String name;
Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread id = %d)%n",
name, Thread.currentThread().threadId());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end");
}
}
}
try (var executorService = Executors.newCachedThreadPool()) {
executorService.submit(new Task("task1"));
executorService.submit(new Task("task2"));
executorService.submit(new Task("task3"));
TimeUnit.SECONDS.sleep(2);
executorService.submit(new Task("task4"));
executorService.submit(new Task("task5"));
}
// 結果
// ↓
//task1 : start (thread id = 33)
//task2 : start (thread id = 34)
//task3 : start (thread id = 35)
//task1 : end
//task2 : end
//task3 : end
//task4 : start (thread id = 33)
//task5 : start (thread id = 35)
//task4 : end
//task5 : end
static ExecutorService newCachedThreadPool (ThreadFactory threadFactory)
class Task implements Runnable {
private final String name;
Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread name = %s)%n",
name, Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end");
}
}
}
try (final var executorService = Executors.newCachedThreadPool(r -> {
final var thread = new Thread(r);
thread.setName("TID:" + thread.threadId());
return thread;
})) {
executorService.submit(new Task("task1"));
executorService.submit(new Task("task2"));
executorService.submit(new Task("task3"));
TimeUnit.SECONDS.sleep(2);
executorService.submit(new Task("task4"));
executorService.submit(new Task("task5"));
}
// 結果
// ↓
//task1 : start (thread name = TID:33)
//task2 : start (thread name = TID:34)
//task3 : start (thread name = TID:35)
//task1 : end
//task2 : end
//task3 : end
//task4 : start (thread name = TID:34)
//task5 : start (thread name = TID:35)
//task4 : end
//task5 : end
static ExecutorService newFixedThreadPool (int nThreads)
class Task implements Runnable {
private final String name;
Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread id = %d)%n",
name, Thread.currentThread().threadId());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end");
}
}
}
try (final var executorService = Executors.newFixedThreadPool(3)) {
executorService.submit(new Task("task1"));
executorService.submit(new Task("task2"));
executorService.submit(new Task("task3"));
executorService.submit(new Task("task4"));
executorService.submit(new Task("task5"));
}
// 結果
// ↓
//task1 : start (thread id = 33)
//task2 : start (thread id = 34)
//task3 : start (thread id = 35)
//task1 : end
//task2 : end
//task3 : end
//task4 : start (thread id = 33)
//task5 : start (thread id = 35)
//task4 : end
//task5 : end
static ExecutorService newFixedThreadPool (int nThreads, ThreadFactory threadFactory)
class Task implements Runnable {
private final String name;
Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread name = %s)%n",
name, Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end");
}
}
}
try (final var executorService = Executors.newFixedThreadPool(3, r -> {
final var thread = new Thread(r);
thread.setName("TID:" + thread.threadId());
return thread;
})) {
executorService.submit(new Task("task1"));
executorService.submit(new Task("task2"));
executorService.submit(new Task("task3"));
executorService.submit(new Task("task4"));
executorService.submit(new Task("task5"));
}
// 結果
// ↓
//task1 : start (thread name = TID:33)
//task2 : start (thread name = TID:34)
//task3 : start (thread name = TID:35)
//task1 : end
//task2 : end
//task3 : end
//task4 : start (thread name = TID:34)
//task5 : start (thread name = TID:35)
//task4 : end
//task5 : end
static ScheduledExecutorService newScheduledThreadPool (int corePoolSize)
class Task implements Runnable {
private final String name;
private final long currentTime;
Task(String name, long currentTime) {
this.name = name;
this.currentTime = currentTime;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread id = %d) : %f sec.%n",
name, Thread.currentThread().threadId(), getElapsedTime());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end : " + getElapsedTime() + " sec.");
}
}
private double getElapsedTime() {
// 基準時点からの経過時刻(秒)
return (System.nanoTime() - currentTime) / 1000000000.0;
}
}
try (final var executorService = Executors.newScheduledThreadPool(3)) {
// 基準となる時刻
final var currentTime = System.nanoTime();
executorService.schedule(new Task("task1", currentTime), 3, TimeUnit.SECONDS);
executorService.schedule(new Task("task2", currentTime), 5, TimeUnit.SECONDS);
executorService.schedule(new Task("task3", currentTime), 7, TimeUnit.SECONDS);
executorService.submit(new Task("task4", currentTime));
executorService.submit(new Task("task5", currentTime));
}
// 結果
// ↓
//task4 : start (thread id = 35) : 0.001707 sec.
//task5 : start (thread id = 34) : 0.001720 sec.
//task4 : end : 1.0058648 sec.
//task5 : end : 1.0060478 sec.
// ※↑scheduleしないものは直後に実行されます。
//task1 : start (thread id = 33) : 3.001571 sec.
//task1 : end : 4.0130198 sec.
//task2 : start (thread id = 34) : 5.010234 sec.
//task2 : end : 6.0181524 sec.
//task3 : start (thread id = 35) : 7.001654 sec.
//task3 : end : 8.0131763 sec.
// ※↑scheduleしたものは、それぞれ3秒後、5秒後、7秒後に実行されます。
static ScheduledExecutorService newScheduledThreadPool (int corePoolSize, ThreadFactory threadFactory)
class Task implements Runnable {
private final String name;
private final long currentTime;
Task(String name, long currentTime) {
this.name = name;
this.currentTime = currentTime;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread name = %s) : %f sec.%n",
name, Thread.currentThread().getName(), getElapsedTime());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end : " + getElapsedTime() + " sec.");
}
}
private double getElapsedTime() {
// 基準時点からの経過時刻(秒)
return (System.nanoTime() - currentTime) / 1000000000.0;
}
}
try (final var executorService = Executors.newScheduledThreadPool(3, r -> {
final var thread = new Thread(r);
thread.setName("TID:" + thread.threadId());
return thread;
})) {
// 基準となる時刻
final var currentTime = System.nanoTime();
executorService.schedule(new Task("task1", currentTime), 3, TimeUnit.SECONDS);
executorService.schedule(new Task("task2", currentTime), 5, TimeUnit.SECONDS);
executorService.schedule(new Task("task3", currentTime), 7, TimeUnit.SECONDS);
executorService.submit(new Task("task4", currentTime));
executorService.submit(new Task("task5", currentTime));
}
// 結果
// ↓
//task4 : start (thread name = TID:34) : 0.005763 sec.
//task5 : start (thread name = TID:35) : 0.005858 sec.
//task4 : end : 1.0167864 sec.
//task5 : end : 1.0167499 sec.
// ※↑scheduleしないものは直後に実行されます。
//task1 : start (thread name = TID:33) : 3.009088 sec.
//task1 : end : 4.0211626 sec.
//task2 : start (thread name = TID:35) : 5.016738 sec.
//task2 : end : 6.0314814 sec.
//task3 : start (thread name = TID:34) : 7.012653 sec.
//task3 : end : 8.0254665 sec.
// ※↑scheduleしたものは、それぞれ3秒後、5秒後、7秒後に実行されます。
static ExecutorService newSingleThreadExecutor ()
class Task implements Runnable {
private final String name;
Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread id = %d)%n",
name, Thread.currentThread().threadId());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end");
}
}
}
try (final var executorService = Executors.newSingleThreadExecutor()) {
executorService.submit(new Task("task1"));
executorService.submit(new Task("task2"));
executorService.submit(new Task("task3"));
}
// 結果
// ↓
//task1 : start (thread id = 33)
//task1 : end
//task2 : start (thread id = 33)
//task2 : end
//task3 : start (thread id = 33)
//task3 : end
// ※↑ひとつのスレッド(上記例ではid=33)のみが使われます。
static ExecutorService newSingleThreadExecutor (ThreadFactory threadFactory)
class Task implements Runnable {
private final String name;
Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread name = %s)%n",
name, Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end");
}
}
}
try (final var executorService = Executors.newSingleThreadExecutor(r -> {
final var thread = new Thread(r);
thread.setName("TID:" + thread.threadId());
return thread;
})) {
executorService.submit(new Task("task1"));
executorService.submit(new Task("task2"));
executorService.submit(new Task("task3"));
}
// 結果
// ↓
//task1 : start (thread name = TID:33)
//task1 : end
//task2 : start (thread name = TID:33)
//task2 : end
//task3 : start (thread name = TID:33)
//task3 : end
// ※↑ひとつのスレッド(上記例ではTID:33)のみが使われます。
static ScheduledExecutorService newSingleThreadScheduledExecutor ()
class Task implements Runnable {
private final String name;
private final long currentTime;
Task(String name, long currentTime) {
this.name = name;
this.currentTime = currentTime;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread id = %d) : %f sec.%n",
name, Thread.currentThread().threadId(), getElapsedTime());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end : " + getElapsedTime() + " sec.");
}
}
private double getElapsedTime() {
// 基準時点からの経過時刻(秒)
return (System.nanoTime() - currentTime) / 1000000000.0;
}
}
try (final var executorService = Executors.newSingleThreadScheduledExecutor()) {
// 基準となる時刻
final var currentTime = System.nanoTime();
executorService.schedule(new Task("task1", currentTime), 3, TimeUnit.SECONDS);
executorService.schedule(new Task("task2", currentTime), 5, TimeUnit.SECONDS);
executorService.submit(new Task("task3", currentTime));
}
// 結果
// ↓
//task3 : start (thread id = 33) : 0.001784 sec.
//task3 : end : 1.0113467 sec.
// ※↑scheduleしないものは直後に実行されます。
//task1 : start (thread id = 33) : 3.009510 sec.
//task1 : end : 4.0228934 sec.
//task2 : start (thread id = 33) : 5.010346 sec.
//task2 : end : 6.0217522 sec.
// ※↑scheduleしたものは、それぞれ3秒後、5秒後に実行されます。
// ひとつのスレッド(上記例ではid=33)のみが使われます。
static ScheduledExecutorService newSingleThreadScheduledExecutor (ThreadFactory threadFactory)
class Task implements Runnable {
private final String name;
private final long currentTime;
Task(String name, long currentTime) {
this.name = name;
this.currentTime = currentTime;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread name = %s) : %f sec.%n",
name, Thread.currentThread().getName(), getElapsedTime());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end : " + getElapsedTime() + " sec.");
}
}
private double getElapsedTime() {
// 基準時点からの経過時刻(秒)
return (System.nanoTime() - currentTime) / 1000000000.0;
}
}
try (final var executorService = Executors.newSingleThreadScheduledExecutor(r -> {
final var thread = new Thread(r);
thread.setName("TID:" + thread.threadId());
return thread;
})) {
// 基準となる時刻
final var currentTime = System.nanoTime();
executorService.schedule(new Task("task1", currentTime), 3, TimeUnit.SECONDS);
executorService.schedule(new Task("task2", currentTime), 5, TimeUnit.SECONDS);
executorService.submit(new Task("task3", currentTime));
}
// 結果
// ↓
//task3 : start (thread name = TID:33) : 0.005336 sec.
//task3 : end : 1.0096395 sec.
// ※↑scheduleしないものは直後に実行されます。
//task1 : start (thread name = TID:33) : 3.001487 sec.
//task1 : end : 4.0157305 sec.
//task2 : start (thread name = TID:33) : 5.012736 sec.
//task2 : end : 6.0237463 sec.
// ※↑scheduleしたものは、それぞれ3秒後、5秒後に実行されます。
// ひとつのスレッド(上記例ではTID:33)のみが使われます。
static ExecutorService newThreadPerTaskExecutor (ThreadFactory threadFactory)
プレビュー機能のためコード例は省略します。
static ExecutorService newVirtualThreadPerTaskExecutor ()
プレビュー機能のためコード例は省略します。
static ExecutorService newWorkStealingPool ()
class Task implements Runnable {
private final String name;
Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread id = %d)%n",
name, Thread.currentThread().threadId());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end");
}
}
}
try (final var executorService = Executors.newWorkStealingPool()) {
executorService.submit(new Task("task1"));
executorService.submit(new Task("task2"));
executorService.submit(new Task("task3"));
executorService.submit(new Task("task4"));
executorService.submit(new Task("task5"));
}
// 結果
// ↓
//task1 : start (thread id = 33)
//task2 : start (thread id = 34)
//task3 : start (thread id = 35)
//task4 : start (thread id = 36)
//task5 : start (thread id = 37)
//task1 : end
//task2 : end
//task3 : end
//task4 : end
//task5 : end
static ExecutorService newWorkStealingPool (int parallelism)
class Task implements Runnable {
private final String name;
Task(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.printf("%s : start (thread id = %d)%n",
name, Thread.currentThread().threadId());
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("Interrupted!");
} finally {
System.out.println(name + " : end");
}
}
}
try (final var executorService = Executors.newWorkStealingPool(3)) {
executorService.submit(new Task("task1"));
executorService.submit(new Task("task2"));
executorService.submit(new Task("task3"));
executorService.submit(new Task("task4"));
executorService.submit(new Task("task5"));
}
// 結果
// ↓
//task1 : start (thread id = 33)
//task2 : start (thread id = 34)
//task3 : start (thread id = 35)
//task1 : end
//task2 : end
//task3 : end
//task4 : start (thread id = 33)
//task5 : start (thread id = 34)
//task4 : end
//task5 : end
static <T> Callable<T> privilegedCallable (Callable<T> callable)
非推奨です。
static <T> Callable<T> privilegedCallableUsingCurrentClassLoader (Callable<T> callable)
非推奨です。
static ThreadFactory privilegedThreadFactory ()
非推奨です。
static ExecutorService unconfigurableExecutorService (ExecutorService executor)
// まずは unconfigurableExecutorService を使わない例です。
try (final var executorService = Executors.newFixedThreadPool(3)) {
// キャストが可能です。
final var threadPoolExecutor = (ThreadPoolExecutor) executorService;
// ThreadPoolExecutor固有の設定も可能となります。
threadPoolExecutor.setCorePoolSize(1);
System.out.println(threadPoolExecutor.getCorePoolSize()); // 1
}
// unconfigurableExecutorService を使う例です。
try (final var executorService = Executors.unconfigurableExecutorService(
Executors.newFixedThreadPool(3))) {
// キャストできません。(ClassCastExceptionが発生します)
final var threadPoolExecutor = (ThreadPoolExecutor) executorService;
// よって、ExecutorServiceをダウンキャストして設定を変更、ということができなくなります。
// これはより厳密性が必要となるプログラムではメリットとなります。
} catch (ClassCastException e) {
System.out.println("ClassCastException!");
}
// 結果
// ↓
//ClassCastException!
static ScheduledExecutorService unconfigurableScheduledExecutorService (ScheduledExecutorService executor)
// まずは unconfigurableScheduledExecutorService を使わない例です。
try (final var scheduledExecutorService = Executors.newScheduledThreadPool(3)) {
// キャストが可能です。
final var threadPoolExecutor = (ScheduledThreadPoolExecutor) scheduledExecutorService;
// ScheduledThreadPoolExecutor固有の設定も可能となります。
threadPoolExecutor.setCorePoolSize(1);
System.out.println(threadPoolExecutor.getCorePoolSize()); // 1
}
// unconfigurableScheduledExecutorService を使う例です。
try (final var scheduledExecutorService = Executors.unconfigurableScheduledExecutorService(
Executors.newScheduledThreadPool(3))) {
// キャストできません。(ClassCastExceptionが発生します)
final var threadPoolExecutor = (ScheduledThreadPoolExecutor) scheduledExecutorService;
// よって、ScheduledExecutorServiceをダウンキャストして設定を変更、ということができなくなります。
// これはより厳密性が必要となるプログラムではメリットとなります。
} catch (ClassCastException e) {
System.out.println("ClassCastException!");
}
// 結果
// ↓
//ClassCastException!
関連記事
- API 使用例
- BlockingQueue (ブロッキング・キュー)
- Callable
- CancellationException
- ConcurrentHashMap.KeySetView (並列処理用セット)
- ConcurrentLinkedDeque (並列処理用・両端キュー)
- ConcurrentLinkedQueue (並列処理用キュー)
- ConcurrentMap (並列処理用マップ)
- ConcurrentModificationException (並列処理例外)
- ConcurrentSkipListSet (並列処理用セット)
- Condition (同期)
- CopyOnWriteArrayList (並列処理用リスト)
- CopyOnWriteArraySet (並列処理用セット)
- CountDownLatch (同期)
- CyclicBarrier (同期)
- Exchanger (同期)
- Executor
- ExecutorService
- Future
- Future.State
- FutureTask
- InterruptedException (割込み例外)
- Lock (同期)
- Object (オブジェクト)
- Runnable
- Semaphore (セマフォ)
- Thread (スレッド)
- ThreadGroup
- ThreadLocal
- TimeUnit