Java : Executors - API使用例

Executors (Java SE 17 & JDK 17) の使用例まとめです。
だいたいのメソッドを網羅済みです。
公式API仕様のおともにどうぞ。


概要

クラス構成

Executors は、ExecutorServiceのインスタンスを作成するユーティリティクラスです。
作成する ExecutorService は大きく分けて5つの種類があります。

メソッド 簡単な説明 使用ケース
newSingleThreadExecutor 1つのスレッドを持つExecutorServiceを作成します。
タスクはその1つのスレッドでのみ実行されます。

タスクAを実行中にタスクBが追加された場合、タスクBはキューに入りタスクAの実行完了を待ちます。
タスクAの実行が完了したら、キューからタスクBが取り出され、スレッド上でタスクBが実行されます。
明確に1つのスレッドのみ使いたい、というケースで使います。
例えば、1つのスレッドに制限することによりsynchronizedを省きたいときです。
newWorkStealingPool​ プロセッサ数に応じたスレッド数を持つExecutorServiceを作成します。

Java 8で新しく追加されました。
いろいろと最適化されていて、パフォーマンスが良いようです。
複数のスレッドで並列処理が必要となるケースでは、だいたいこれでよいのではないかなと思います。
newScheduledThreadPool​ ScheduledExecutorServiceを作成します。

ScheduledExecutorServiceはタスクをスケジューリングできます。
例えば、1分後にタスクを実行、というような使い方ができます。
タスクのスケジューリングが必要となるケースで使います。
newFixedThreadPool 指定した固定数のスレッドを持つExecutorServiceを作成します。

スレッドはExecutorService.shutdownするまで残り続けます。
明確な理由がなければ、代わりにnewWorkStealingPoolでよいかと思います。
newCachedThreadPool
複数のスレッドを持つExecutorServiceを作成します。

スレッドは60秒間使われないと、キャッシュから削除され解放されます。
ここがnewFixedThreadPoolと違う点です。

タスクが追加されスレッドが必要になると、再度スレッドが生成されます。
API仕様には、"通常、これらのプールは、短期の非同期タスクを多数実行するプログラムのパフォーマンスを改善します。 "とあります。

プールを使用していない時間はスレッドが解放されているので、リソース的には優しいです。
その代わり、スレッドが必要になったときに、スレッドの再作成が必要となるので、その分の処理がかかります。

複数スレッドによる並列処理が必要な場合は、新しいAPIである newWorkStealingPool がおすすめです。
パフォーマンスがどうも悪いな、と感じたら newFixedThreadPool や newCachedThreadPool などに置き換えてチューニングしていく感じでよいかなと思います。

ただし、newWorkStealingPool には注意点があります。
newWorkStealingPool で作成した ExecutorService に対して、Future.cancel(true) によるスレッドの割込みは効果がないようです。

どうも newWorkStealingPoolは、内部では ForkJoinPoolを使用しており、そのFutureはForkJoinTask になります。

public boolean cancel(boolean mayInterruptIfRunning)
...
パラメータ:
mayInterruptIfRunning - 取消しの制御に割込みは使用されないため、デフォルトの実装ではこの値に効果はありません。

ForkJoinTask.cancel のパラメータ( mayInterruptIfRunning ) の説明に、デフォルトの実装では効果なし、と説明があります。
外部サイトで英語ですが、以下の記事も参考にお願いします。

日本語訳の注意点

API仕様の日本語訳に、"共有アンバウンド形式のキューなしで動作"という表現があります。
これは、正確には "サイズ制限のない共有キューを使って動作" という意味になります。ご注意ください。

メソッド

static Callable<Object> callable (Runnable task)

呼出し時に、指定されたタスクを実行し、nullを返す、Callableオブジェクトを返します。

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)

呼出し時に、指定されたタスクを実行し、指定された結果を返す、Callableオブジェクトを返します。

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)

呼出し時に、指定された特権付きアクションを実行し、その結果を返す、Callableオブジェクトを返します。

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)

呼出し時に、指定された特権付き例外アクションを実行し、その結果を返す、Callableオブジェクトを返します。

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.getId());
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 : 19
//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.println("%s : start (thread id = %d)".formatted(
                    name, Thread.currentThread().getId()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end");
        }
    }
}

final var executorService = Executors.newCachedThreadPool();
try {
    executorService.submit(new Task("task1"));
    executorService.submit(new Task("task2"));
    executorService.submit(new Task("task3"));

    Thread.sleep(2000);

    executorService.submit(new Task("task4"));
    executorService.submit(new Task("task5"));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task1 : start (thread id = 19)
//task2 : start (thread id = 20)
//task3 : start (thread id = 21)
//task1 : end
//task2 : end
//task3 : end
//task4 : start (thread id = 19)
//task5 : start (thread id = 20)
//task4 : end
//task5 : end
//term : true

static ExecutorService newCachedThreadPool (ThreadFactory threadFactory)

必要に応じ、新規スレッドを作成するスレッド・プールを作成しますが、利用可能な場合には以前に構築されたスレッドを再利用します。また、必要に応じ、指定されたThreadFactoryを使用して新規スレッドを作成します。

class Task implements Runnable {
    private final String name;

    Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        try {
            System.out.println("%s : start (thread name = %s)".formatted(
                    name, Thread.currentThread().getName()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end");
        }
    }
}

final var executorService = Executors.newCachedThreadPool(r -> {
    final var thread = new Thread(r);
    thread.setName("TID:" + thread.getId());
    return thread;
});

try {

    executorService.submit(new Task("task1"));
    executorService.submit(new Task("task2"));
    executorService.submit(new Task("task3"));

    Thread.sleep(2000);

    executorService.submit(new Task("task4"));
    executorService.submit(new Task("task5"));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task1 : start (thread name = TID:19)
//task2 : start (thread name = TID:20)
//task3 : start (thread name = TID:21)
//task1 : end
//task2 : end
//task3 : end
//task4 : start (thread name = TID:20)
//task5 : start (thread name = TID:19)
//task4 : end
//task5 : end
//term : true

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.println("%s : start (thread id = %d)".formatted(
                    name, Thread.currentThread().getId()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end");
        }
    }
}

final var executorService = Executors.newFixedThreadPool(3);
try {
    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"));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task1 : start (thread id = 19)
//task2 : start (thread id = 20)
//task3 : start (thread id = 21)
//task1 : end
//task2 : end
//task3 : end
//task4 : start (thread id = 19)
//task5 : start (thread id = 20)
//task4 : end
//task5 : end
//term : true

static ExecutorService newFixedThreadPool (int nThreads, ThreadFactory threadFactory)

共有アンバウンド形式のキューなしで動作する、固定数のスレッドを再利用するスレッド・プールを作成します。必要に応じ、指定されたThreadFactoryを使用して新規スレッドを作成します。

class Task implements Runnable {
    private final String name;

    Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        try {
            System.out.println("%s : start (thread name = %s)".formatted(
                    name, Thread.currentThread().getName()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end");
        }
    }
}

final var executorService = Executors.newFixedThreadPool(3, r -> {
    final var thread = new Thread(r);
    thread.setName("TID:" + thread.getId());
    return thread;
});

try {
    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"));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task1 : start (thread name = TID:19)
//task2 : start (thread name = TID:20)
//task3 : start (thread name = TID:21)
//task1 : end
//task2 : end
//task3 : end
//task4 : start (thread name = TID:19)
//task5 : start (thread name = TID:21)
//task4 : end
//task5 : end
//term : true

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.println("%s : start (thread id = %d) : %f sec.".formatted(
                    name, Thread.currentThread().getId(), getElapsedTime()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end : " + getElapsedTime() + " sec.");
        }
    }

    private double getElapsedTime() {
        // 基準時点からの経過時刻(秒)
        return (System.nanoTime() - currentTime) / 1000000000.0;
    }
}

final var executorService = Executors.newScheduledThreadPool(3);
try {
    // 基準となる時刻
    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));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task4 : start (thread id = 19) : 0.001506 sec.
//task5 : start (thread id = 20) : 0.001513 sec.
//task4 : end : 1.006481 sec.
//task5 : end : 1.006481 sec.

// ※↑scheduleしないものは直後に実行されます。

//task1 : start (thread id = 21) : 3.006325 sec.
//task1 : end : 4.0194767 sec.
//task2 : start (thread id = 20) : 5.004635 sec.
//task2 : end : 6.0051288 sec.
//task3 : start (thread id = 19) : 7.010179 sec.
//task3 : end : 8.0113855 sec.
//term : true

// ※↑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.println("%s : start (thread name = %s) : %f sec.".formatted(
                    name, Thread.currentThread().getName(), getElapsedTime()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end : " + getElapsedTime() + " sec.");
        }
    }

    private double getElapsedTime() {
        // 基準時点からの経過時刻(秒)
        return (System.nanoTime() - currentTime) / 1000000000.0;
    }
}

final var executorService = Executors.newScheduledThreadPool(3, r -> {
    final var thread = new Thread(r);
    thread.setName("TID:" + thread.getId());
    return thread;
});

try {
    // 基準となる時刻
    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));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task4 : start (thread name = TID:19) : 0.004001 sec.
//task5 : start (thread name = TID:20) : 0.004001 sec.
//task4 : end : 1.0137487 sec.
//task5 : end : 1.0137474 sec.

// ※↑scheduleしないものは直後に実行されます。

//task1 : start (thread name = TID:21) : 3.002379 sec.
//task1 : end : 4.0163815 sec.
//task2 : start (thread name = TID:19) : 5.006053 sec.
//task2 : end : 6.0197621 sec.
//task3 : start (thread name = TID:20) : 7.006731 sec.
//task3 : end : 8.010247 sec.
//term : true

// ※↑scheduleしたものは、それぞれ3秒後、5秒後、7秒後に実行されます。

static ExecutorService newSingleThreadExecutor ()

アンバウンド形式のキューなしで動作する、単一のワーカー・スレッドを使用するexecutorを作成します。

class Task implements Runnable {
    private final String name;

    Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        try {
            System.out.println("%s : start (thread id = %d)".formatted(
                    name, Thread.currentThread().getId()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end");
        }
    }
}

final var executorService = Executors.newSingleThreadExecutor();
try {
    executorService.submit(new Task("task1"));
    executorService.submit(new Task("task2"));
    executorService.submit(new Task("task3"));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task1 : start (thread id = 19)
//task1 : end
//task2 : start (thread id = 19)
//task2 : end
//task3 : start (thread id = 19)
//task3 : end
//term : true

// ※↑ひとつのスレッド(上記例ではid=19)のみが使われます。

static ExecutorService newSingleThreadExecutor (ThreadFactory threadFactory)

アンバウンド形式のキューなしで動作する、単一のワーカー・スレッドを使用するexecutorを作成します。必要に応じて、指定されたThreadFactoryを使用して新規スレッドを作成します。

class Task implements Runnable {
    private final String name;

    Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        try {
            System.out.println("%s : start (thread name = %s)".formatted(
                    name, Thread.currentThread().getName()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end");
        }
    }
}

final var executorService = Executors.newSingleThreadExecutor(r -> {
    final var thread = new Thread(r);
    thread.setName("TID:" + thread.getId());
    return thread;
});

try {
    executorService.submit(new Task("task1"));
    executorService.submit(new Task("task2"));
    executorService.submit(new Task("task3"));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task1 : start (thread name = TID:19)
//task1 : end
//task2 : start (thread name = TID:19)
//task2 : end
//task3 : start (thread name = TID:19)
//task3 : end
//term : true

// ※↑ひとつのスレッド(上記例ではTID:19)のみが使われます。

static ScheduledExecutorService newSingleThreadScheduledExecutor ()

指定された遅延時間後、または周期的にコマンドの実行をスケジュールできる、単一スレッドのexecutorを作成します。

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.println("%s : start (thread id = %d) : %f sec.".formatted(
                    name, Thread.currentThread().getId(), getElapsedTime()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end : " + getElapsedTime() + " sec.");
        }
    }

    private double getElapsedTime() {
        // 基準時点からの経過時刻(秒)
        return (System.nanoTime() - currentTime) / 1000000000.0;
    }
}

final var executorService = Executors.newSingleThreadScheduledExecutor();
try {
    // 基準となる時刻
    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));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task3 : start (thread id = 19) : 0.001647 sec.
//task3 : end : 1.0058912 sec.

// ※↑scheduleしないものは直後に実行されます。

//task1 : start (thread id = 19) : 3.004922 sec.
//task1 : end : 4.0058481 sec.
//task2 : start (thread id = 19) : 5.016109 sec.
//task2 : end : 6.0202343 sec.
//term : true

// ※↑scheduleしたものは、それぞれ3秒後、5秒後に実行されます。
// ひとつのスレッド(上記例ではid=19)のみが使われます。

static ScheduledExecutorService newSingleThreadScheduledExecutor (ThreadFactory threadFactory)

指定された遅延時間後、または周期的にコマンドの実行をスケジュールできる、単一スレッドのexecutorを作成します。

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.println("%s : start (thread name = %s) : %f sec.".formatted(
                    name, Thread.currentThread().getName(), getElapsedTime()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end : " + getElapsedTime() + " sec.");
        }
    }

    private double getElapsedTime() {
        // 基準時点からの経過時刻(秒)
        return (System.nanoTime() - currentTime) / 1000000000.0;
    }
}

final var executorService = Executors.newSingleThreadScheduledExecutor(r -> {
    final var thread = new Thread(r);
    thread.setName("TID:" + thread.getId());
    return thread;
});

try {
    // 基準となる時刻
    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));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task3 : start (thread name = TID:19) : 0.005357 sec.
//task3 : end : 1.0174043 sec.

// ※↑scheduleしないものは直後に実行されます。

//task1 : start (thread name = TID:19) : 3.009057 sec.
//task1 : end : 4.0206572 sec.
//task2 : start (thread name = TID:19) : 5.009596 sec.
//task2 : end : 6.0108232 sec.
//term : true

// ※↑scheduleしたものは、それぞれ3秒後、5秒後に実行されます。
// ひとつのスレッド(上記例ではTID:19)のみが使われます。

static ExecutorService newWorkStealingPool ()

ターゲット並列処理レベルとして「利用可能なプロセッサ」の数を使用して、ワーク・スティール・スレッド・プールを作成します。

class Task implements Runnable {
    private final String name;

    Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        try {
            System.out.println("%s : start (thread id = %d)".formatted(
                    name, Thread.currentThread().getId()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end");
        }
    }
}

final var executorService = Executors.newWorkStealingPool();
try {
    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"));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task1 : start (thread id = 19)
//task2 : start (thread id = 20)
//task3 : start (thread id = 21)
//task4 : start (thread id = 22)
//task5 : start (thread id = 23)
//task1 : end
//task2 : end
//task3 : end
//task4 : end
//task5 : end
//term : true

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.println("%s : start (thread id = %d)".formatted(
                    name, Thread.currentThread().getId()));

            Thread.sleep(1000);

        } catch (InterruptedException e) {
            System.out.println("Interrupted!");
        } finally {
            System.out.println(name + " : end");
        }
    }
}

final var executorService = Executors.newWorkStealingPool(3);
try {
    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"));

} finally {
    executorService.shutdown();
}

final var ret = executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("term : " + ret);

// 結果
// ↓
//task1 : start (thread id = 19)
//task2 : start (thread id = 20)
//task3 : start (thread id = 21)
//task1 : end
//task2 : end
//task3 : end
//task4 : start (thread id = 21)
//task5 : start (thread id = 20)
//task4 : end
//task5 : end
//term : true

static <T> Callable<T> privilegedCallable (Callable<T> callable)

削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。

非推奨です。

static <T> Callable<T> privilegedCallableUsingCurrentClassLoader (Callable<T> callable)

削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。

非推奨です。

static ThreadFactory privilegedThreadFactory ()

削除予定のため非推奨: このAPI要素は、将来のバージョンで削除される可能性があります。

非推奨です。

static ExecutorService unconfigurableExecutorService (ExecutorService executor)

定義済みのすべてのExecutorServiceメソッドを指定されたexecutorに委譲するが、キャストを使用してアクセス可能なほかのメソッドは委譲しないオブジェクトを返します。

// まずは unconfigurableExecutorService を使わない例です。
final var executorService = Executors.newFixedThreadPool(3);

try {
    // キャストが可能です。
    final var threadPoolExecutor = (ThreadPoolExecutor) executorService;

    // ThreadPoolExecutor固有の設定も可能となります。
    threadPoolExecutor.setCorePoolSize(1);
    System.out.println(threadPoolExecutor.getCorePoolSize()); // 1

} finally {
    executorService.shutdown();
}
// unconfigurableExecutorService を使う例です。
final var executorService = Executors.unconfigurableExecutorService(
        Executors.newFixedThreadPool(3));

try {
    // キャストできません。(ClassCastExceptionが発生します)
    final var threadPoolExecutor = (ThreadPoolExecutor) executorService;

    // よって、ExecutorServiceをダウンキャストして設定を変更、ということができなくなります。
    // これはより厳密性が必要となるプログラムではメリットとなります。

} catch (ClassCastException e) {
    System.out.println("ClassCastException!");
} finally {
    executorService.shutdown();
}

// 結果
// ↓
//ClassCastException!

static ScheduledExecutorService unconfigurableScheduledExecutorService (ScheduledExecutorService executor)

定義済みのすべてのScheduledExecutorServiceメソッドを指定されたexecutorに委譲するが、キャストを使用してアクセス可能なほかのメソッドは委譲しないオブジェクトを返します。

// まずは unconfigurableScheduledExecutorService を使わない例です。
final var scheduledExecutorService = Executors.newScheduledThreadPool(3);

try {
    // キャストが可能です。
    final var threadPoolExecutor = (ScheduledThreadPoolExecutor) scheduledExecutorService;

    // ScheduledThreadPoolExecutor固有の設定も可能となります。
    threadPoolExecutor.setCorePoolSize(1);
    System.out.println(threadPoolExecutor.getCorePoolSize()); // 1

} finally {
    scheduledExecutorService.shutdown();
}
// unconfigurableScheduledExecutorService を使う例です。
final var scheduledExecutorService = Executors.unconfigurableScheduledExecutorService(
        Executors.newScheduledThreadPool(3));

try {
    // キャストできません。(ClassCastExceptionが発生します)
    final var threadPoolExecutor = (ScheduledThreadPoolExecutor) scheduledExecutorService;

    // よって、ScheduledExecutorServiceをダウンキャストして設定を変更、ということができなくなります。
    // これはより厳密性が必要となるプログラムではメリットとなります。

} catch (ClassCastException e) {
    System.out.println("ClassCastException!");
} finally {
    scheduledExecutorService.shutdown();
}

// 結果
// ↓
//ClassCastException!

関連記事

ページの先頭へ