2

私のコードには、発生してはならないスレッドの問題がありますが、発生しています。だから私はいくつかの回避策を作ろうとしています。できるだけ簡単なコードで問題を説明しようとします-問題が発生しているコードは大きくて複雑なので、コードを短くすると:

...................
..................
void createAndRunThreads(){
   List<Path> pathList = //read path from DB readPath();
   for(Path p : pathList){
      RunJob rj = new RunJob(p);
      Thred t = new Thread(rj);
      t.start();
   }
}

class RunJob implements Runnable {
   private Path path;
   private ExecuteJob execJob;

   public RunJob(Path path){
      this.path = path;
      this.execJob = new ExecuteJob();
   }

   public void run() {
      execJob.execute(path);
   }

}

class ExecuteJob {

   private static Job curentExecutingJob;

   public void execute(Path path){
      //here every thread should get different job list from others but this is not happening
      //so what happens eventually two threads are executing the same Job at once and it gets messy
      List<Job> jobList = getJobsFromPath(path);

      for(Job job : jobList) {
         curentExecutingJob=job;

         //work around that I'm trying to do. So if other thread tries to run the same job has to wait on lock(I dont know if this is posible do) 
         synchronized(curentExecutingJob){
            if(job.getStatus.equals("redy")){
               //do sum initialization 
               //and databese changes 
               job.run();
            }   
         }  
      }
   }

}

したがって、私の懸念はこれが機能するかどうかです-ロック内のオブジェクトがメモリ(正確なオブジェクトである必要がある)またはequals(equalsを実装するために)によって比較されるかどうかはわかりません

静的な currentExecutingJob メンバーが最初のスレッドに 1 つの値オブジェクトを持ち、(同期ブロックで) その上にロックを作成し、2 番目のスレッドがその値を変更して同期ブロックに入ろうとするとどうなりますか (私が期待しているのはそのスレッドです) -2 は実行を継続し、それがブロックされるのは、以前に最初のスレッドが取得したのと同じジョブを DB から取得するときのみです)

このアプローチが可能であり、意味があるかどうかはわかりません

2 つのスレッドが、メソッド内にある次のコードを実行しています。

1    Job j = getJobByIdFromDB(1111);
2    if(j.status.equals("redye")){
3        do staff
4        make database changes 
5        j.run();
6        j.state="running";
7    }

ThreadA は JVM から 3 行目で実行を停止され、その状態は実行中から実行可能に変更され、ポーリングで待機するように設定されます。

ThreadB は JVM によってチャンスを与えられ、ThreadB は、私が望んでいない行 1、2、3、4、5、6 を実行します。残りのスレッドの誰かが同じコードを入力する機会を得る前に、2 行目と 3 行目でコードに入る最初のスレッドを終了させたい

これを達成する問題は、2つのスレッドが異なるインスタンスでサンプルメソッドを実行しているため、メソッド全体が同期されていないことです-また、このメソッドで実行された他のコードがあり、それを同期させたくありませ
ん私の問題の解決策 また、synchronized(this.class){} を作成すると、マルチスレッドの利点と意味が失われます

4

3 に答える 3

1

問題は、「currentExecutingJob」が静的として定義されていることです。これは、ExecuteJob のすべてのインスタンスがこの変数の同じ「インスタンス」を共有することを意味します。さらに、同期ブロックの外でこの変数の値を設定しています。つまり、各スレッドは制御されない方法で値を設定します。次の同期ブロックは、実際にはまったく影響を与えません。

サンプル コードの記述方法を考えると、複数のスレッド間で共有されるリソースがないため、静的変数は必要なく、同期も必要ないように思えます。

ただし、コード内のコメントは、2 つのスレッドが同じジョブを同時に実行しないようにすることを示しています。同じジョブが実行されているかどうかを確認するための実行中のジョブの比較がないため、コードはこれを達成しません。また、比較があったとしても、 getJobsFromPath() は同じオブジェクトインスタンスが実行されるようにジョブリストを作成する必要があります。 2 つのスレッド/パスが同じ「ジョブ」に遭遇した場合は、再利用する必要があります。

あなたのコードにはこれが見当たりません。

于 2013-08-06T12:48:22.163 に答える
0

コメントできないので、答えとして入れます。ごめん。

ブロック

同期 (currentExecutingJob)

オブジェクト currentExecutingJob で同期します(あなたの言葉では、メモリ)。currentExecutingJob.equals(otherExecutingJob) == true で別のオブジェクト otherExecutingJob を同期する場合、両方の同期ステートメントは互いに影響しません。

あなたの質問/問題に対して: getJobsFromPath が何をしているのか、何をすべきなのか、実際に何をしたいのか、実際に何が問題なのかを説明していただけると助かります。私にはよくわかりません。

于 2013-08-06T12:43:10.907 に答える
0

準備ができているかどうか、ジョブのステータスをチェックするコードを見ましたが、これは実行可能な方法ではないと思います

Runnable の代わりに Callable Interface を使用できます

ここにあなたを助けるかもしれない詳細な例があります。

Java 並行性

于 2013-08-06T12:46:48.303 に答える