Java : Executors - API使用例

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


概要

このパッケージで定義されたExecutor、ExecutorService、ScheduledExecutorService、ThreadFactory、およびCallableクラス用のファクトリおよびユーティリティ・メソッドです。

クラス構成

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 になります。


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

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

もし、Future.cancel(true) によるスレッド割込みを行いたいケースでは、代わりに newFixedThreadPool を使うことも検討してみましょう。


日本語訳の注意点

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.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)

必要に応じ、新規スレッドを作成するスレッド・プールを作成しますが、利用可能な場合には以前に構築されたスレッドを再利用します。また、必要に応じ、指定された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)

共有アンバウンド形式のキューなしで動作する、固定数のスレッドを再利用するスレッド・プールを作成します。必要に応じ、指定された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 ()

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

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)

アンバウンド形式のキューなしで動作する、単一のワーカー・スレッドを使用するexecutorを作成します。必要に応じて、指定された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 ()

指定された遅延時間後、または周期的にコマンドの実行をスケジュールできる、単一スレッドの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.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)

指定された遅延時間後、または周期的にコマンドの実行をスケジュールできる、単一スレッドの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.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)

Preview. タスクごとに新しいスレッドを開始するエグゼキュータを作成します。

プレビュー機能のためコード例は省略します。

static ExecutorService newVirtualThreadPerTaskExecutor ()

Preview. タスクごとに新しい仮想スレッドを開始するエグゼキュータを作成します。

プレビュー機能のためコード例は省略します。

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)

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

非推奨です。

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

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

非推奨です。

static ThreadFactory privilegedThreadFactory ()

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

非推奨です。

static ExecutorService unconfigurableExecutorService (ExecutorService executor)

定義済みのすべての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)

定義済みのすべての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!

関連記事

ページの先頭へ