1

複数の実行可能なクラスがあり、それらを一元化されたクラス (すべての実行可能なクラスのリストを含む Launcher クラスと呼びます) を介してエグゼキューター サービスで実行したいと考えています。

Launcher使用してすべての Bean をインスタンス化するクラスを作成しapplicationContext.getBean()ました。各ランナブル クラスはpool sizefor it (このランナブルに対して生成するスレッドの数) も定義します。

public class DaemonsLauncher {

    @Autowired
    private ApplicationContext appContext;

    private List<Daemon> daemons = new ArrayList<Daemon>();

    private ScheduledThreadPoolExecutor executor;

    private void initThreadPool() throws Exception {
        //daemonNames coming at run time from somewhere.
        List<String> daemonList = Arrays.asList(daemonNames.split(Constant.COMMA));
        //Pool size will now be summation of all the pool sizes.
        int poolSize = 0;
        for (String dName : daemonList) {
            Daemon daemon = appContext.getBean(dName, Daemon.class);
            poolSize += daemon.getPoolSize();
            daemons.add(daemon);
        }
        executor = new ScheduledThreadPoolExecutor(poolSize);
    }

    public void launchDaemons() throws Exception {
        for (Daemon daemon : daemons) {
            for (int currentThreadCount = 1; currentThreadCount <= daemon.getPoolSize(); currentThreadCount++) {
                executor.scheduleWithFixedDelay(daemon, 0, XYZ, ABC);
            }
        }
    }
}

その過程で、すべてのランナブルを a に追加しますList<Daemon>(デーモンは、他のデーモンによって拡張される抽象ランナブル クラスです)。

public abstract class Daemon implements Runnable {

    protected int poolSize = 1;

    public int getPoolSize() {
        return poolSize;
    }

    @Override
    public void run() {
        //Calls run methods of individual runnables here.
    }

}

ご覧のとおり、実行中に各実行可能なクラスの同じインスタンスを (poolSize に応じて) 複数回追加します。

executorであることScheduledThreadPoolExecutor

のrunメソッドが呼び出された瞬間、(hasCodeとtoStringを印刷することでチェックされた)R一度だけ取得されたため、実行可能なクラスの同じインスタンスが両方の時間で見つかりました。appContext.getBean()

ただし、実行可能なクラスのこれらの複数のインスタンスは同時に実行されます。

この種のケースでは何が問題になる可能性がありますか? これらの複数のスレッドが同じランナブルに対して実行されていると、問題が発生しますか?それともうまくいきますか?

別の方法として、poolSize に応じて、このループの前でも Runnable クラスの複数のインスタンスを取得し、List に存在するすべての「Runnable」エントリに応じて 1 回だけループすることができます。

  1. すべての Bean は本質的にプロトタイプです (ただし、appContext.getBean を 1 回しか呼び出していないため、全体像はわかりません)。
  2. A. sample Runnable class_

    public class R extends Daemon {
        @Override
        public void runIndividualDaemon() {
            //Called by run of Daemon class.
            logger.info("Running Daemon." + this.hashCode() + " " + this.toString());
        }
    
        @Override
        protected void init() throws Exception {
            this.poolSize = 5;
        }
    }
    
4

2 に答える 2

2

タスクが複数回実行されている場合は、それを複数回追加したことが原因です。

これを確認するために、タスクを追加するときにログを記録することをお勧めします。

しかし、同じスレッドが 2 つのスレッドのタスクを実行しているのはどうしてでしょうか?

スレッドは一度に 2 つのタスクを実行することはできませんが、同じスレッドを再利用して次々とタスクを実行できます。

その Bean がシングルトンの場合はそうではなかった「「Runnable」クラスのインスタンスが 2 つある」ということですか?

この場合、同じタスクを2つ追加したり、同じタスクを2回追加したりすることで大きな違いが生じるとは思いません。

于 2012-10-31T15:52:41.637 に答える
0

Daemon クラスはスレッドセーフではないため、複数のスレッドから (タイプ Runnable の) 同じインスタンスを実行するのは危険です。オブジェクトへのアクセスがモニター (synchronized キーワード) で保護されていない限り、複数のスレッドから同じインスタンスのメソッドを実行することは常に危険です。

次に、プール内のすべてのスレッドが単一の Runnable オブジェクトのみを実行します。スレッド プールは、小さな Runnable が多数あるが、インスタンスごとにスレッドを消費したくないユース ケース向けに設計されています。あなたのタスクはデータベースをポーリングすることなので、タスクごとにスレッドを持つことは論理的ですが、スレッドプールを作成する必要はありません。タスクごとに新しいスレッドを開始するだけです (daemonList のいくつかのクラスの複数のスレッドを含む)。

あなたは次のように書いています:「しかし、実行可能なクラスのこれらの複数のインスタンスは同時に実行されます」。もちろん、そのようにプログラムしたからです。スレッドは、物事を同時に実行するための機能です。また、スレッドが実行するタスクとして Runnable タイプの同じオブジェクトまたは異なるオブジェクトを取るかどうかは問題ではありません。

于 2012-10-31T17:13:05.913 に答える