0

私のアプリケーションでは、タスクを作成する複数のschedulerスレッドがあります。たとえばについて各スケジューラスレッドはタスクの束を作成することができます。複数のスケジュールスレッド送信タスクRejectedExecutionException

TaskCreator tastCreator; 
for (Report report: report) { 
    taskCreator.createTask(report); 
} 

あなたはログから見ることができるようにスケジューラ・スレッドが同時に実行することができます。

15:57:20.107 INFO [ scheduler-4] c.task.ReportExportSchedulerTask : Task created 
15:57:20.107 INFO [ scheduler-2] c.task.ReportExportSchedulerTask : Task created 

それが通る次のように私はTaskCreatorコンポーネントを持っていますexecuteJob()にタスク:

@Component 
public class TaskCreator { 
    @Autowired 
    private SftpTaskExecutor sftpTaskExecutor; 
    @Autowired 
    SftpConfig sftpConfig; 

    @Autowired 
    private SFTPConnectionManager connectionManager; 

    public void createTask(Report report) { 
     sftpTaskExecutor.executeJob(new JobProcessorTask(...)); 
    } 

    public void validateTasksExecution() { 
     sftpTaskExecutor.getExecutorService().shutdown(); 
     while (!sftpTaskExecutor.getExecutorService().isTerminated()) ; 
     connectionManager.disconnect(); 
    } 
} 

SftpTaskExecutorComponentに私は上記のタスクを提出するexecutorServiceを構築することを次のように二つ以上のスケジューラスレッドがタスクを作成し、同時にサービスをエグゼキュータに提出されているが、上記RejectedExecutionExceptionをスローした場合私の質問は、ある

@Component 
public class SftpTaskExecutor { 
    private ExecutorService executorService = Executors.newSingleThreadExecutor(); 

    public void executeJob(JobProcessorTask jobProcessorTask) { 
     executorService.execute(jobProcessorTask); 
    } 

    public ExecutorService getExecutorService() { 
     return executorService; 
    } 
} 

1つのスケジューラタスクが完了していない(すなわち各スケジュールスレッドの場合は送信されません)

ファイル、私は他のスケジューラ・スレッドに干渉することなくvalidateTasksExecution()を呼び出すことができるようにする必要があります。言い換えれば、他のスケジューラがまだ処理していない間に切断しないでください。

私はこれに関して正しくExecutorServiceを使用していますか?上記をスレッドセーフにするにはどうすればよいですか?

+0

役に立つと思われる場合は必ず回答を受け入れるようにしてください。 – Gray

答えて

0

二つ以上のスケジューラのスレッドがタスクを作成し、同時にサービスをエグゼキュータに提出された場合私の質問は、上記完成していない1つのスケジューラのタスク(つまり、送信されていないファイル)が

ましょうとのRejectedExecutionExceptionをスローされますjavadocs for ExecutorService.execute(...)

RejectedExecutionException - このタスクを実行することができない場合は、このタスクを実行してください。 ThreadPoolExecutor(および関連する)の​​コードを見て

、ジョブが2つの理由で拒否されます:

  • キュージョブのキューがあるので(これはあなたには適用されませんいっぱいです無制限デフォルト)
  • エグゼキュータのサービスはもはや実行されている
  • (鼎鼎鼎)

で私はあなたのスレッドの最初は持っているので、あなたのエグゼキュータのサービスは、最も可能性の高いシャットダウンをされていると信じています第2のスレッドがexecuteJob(...)を呼び出す前にvalidateTasksExecution()と呼ばれます。そのスレッドプールを再利用しようとすると、コードが正しくありません。 connectionManager()も閉鎖しているので、SftpTaskExecutorを再利用したいのかどうか疑問に思います。

あなたはその操作が行われた場合、各スレッドは見たいけど、スレッドプールの滞在が稼働しているなら、あなたはExecutorService.submit(...)方法からFuture(s)を保存する必要があり、それらにget()を呼び出します。それは仕事がいつ終わるかをあなたに伝えます。以下のような

何か:

public Future<Void> createTask(Report report) { 
    return sftpTaskExecutor.executeJob(new JobProcessorTask(...)); 
} 

public void validateTasksExecution(Future<Void> future) { 
    // there is some exceptions here you need to handle 
    future.get(); 
} 

public void shutdown() { 
    sftpTaskExecutor.shutdown(); 
    connectionManager.disconnect(); 
} 

... 

public Future<Void> executeJob(JobProcessorTask jobProcessorTask) { 
    return executorService.submit(jobProcessorTask); 
} 

あなたは、あなたがコレクションに保存する必要があり、複数のジョブを監視し、ジョブを並行して実行されますが、シリアルそれらにget()を呼び出す必要がある場合

代わりに、トランザクションごとに別々のExecutorServiceを持たせてください。これは無駄ですが、sftp呼び出しを管理していることを考えると悪くないかもしれません。

while (!sftpTaskExecutor.getExecutorService().isTerminated()) ; 

うん、あなたはそのようにスピンする必要はありません。 awaitTermination(...) javadocsを参照してください。

関連する問題