2016-07-26 41 views
0

Executableサービス(アンバウンド・キューを持つシングル・スレッド)に実行可能オブジェクトをサブミットした後、その実行可能オブジェクトを変更できますか?例えば実行可能オブジェクトをExecutorServiceに提出した後で実行可能オブジェクトを変更しますか?

:あなたは上記の例でわかるように、我々は実行可能なオブジェクトを提出し、あまりにもループ内のオブジェクトの内容を変更する場合

public class Test { 
    @Autowired 
    private Runner userRunner; 

    @Autowired 
    private ExecutorService executorService; 

    public void init() { 
     for (int i = 0; i < 100; ++i) { 
      userRunner.add("Temp" + i); 
      Future runnerFuture = executorService.submit(userRunner); 
     } 
    } 
} 

public class Runner implements Runnable { 
    private List<String> users = new ArrayList<>(); 

    public void add(String user) { 
     users.add(user); 
    } 

    public void run() { 
     /* Something here to do with users*/ 
    } 
} 

、第一、サービスが使用エグゼキュータして提出します新しく追加されたユーザー。 runメソッドが何かを本当に集中的に実行しており、その後のサブミットがキューに入れられていると考えてください。

答えて

1

実行可能オブジェクトをサブミットし、ループの内部でオブジェクトの内容を変更すると、1番目の実行者サービスには、新しく追加されたユーザーが使用されます。

usersArrayListが適切に同期されている場合のみ。あなたがしているのは、例外やその他の予測不可能な結果を​​引き起こす可能性がある2つの異なるスレッドからusersフィールドを変更しようとしていることです。同期によって相互排他が保証され、複数のスレッドが同時に予期せず同時に変更されないようにすると同時に、1つのスレッドの変更が他のスレッドの変更を確実に示すメモリ同期も実現します。あなたは何ができるか

はあなたの例に同期を追加することです:

public void add(String user) { 
    synchronized (users) { 
     users.add(user); 
    } 
} 
... 

public void run() { 
    synchronized (users) { 
     /* Something here to do with users*/ 
    } 
} 

別のオプションは、リストを同期するために、次のようになります。

// you can't use this if you are iterating on this list (for, etc.) 
private List<String> users = Collections.synchronizedList(new ArrayList<>()); 

しかし、あなたはあなたの場合は、手動で同期する必要がありますリスト上でforループを使用しているか、それ以外の場合は反復処理を行っています。

0

最もクリーンで最も単純なアプローチは、未来をキャンセルしてから、更新されたユーザーリストを使って新しいタスクを送信することです。そうしないと、スレッド間でリストを改ざんすることによる可視性の問題に直面するだけでなく、既に実行中のタスクを変更しているかどうかを知る方法がありません。

関連する問題