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(在其上实现相等)进行比较

当静态curentExecutingJob成员在第一个线程中有一个值对象并在其上创建锁(在同步块中)并且第二个线程更改该值并尝试进入同步块时会发生什么(我希望成为那个线程-2 将继续执行,只有当他将从 DB 中获得与之前第一个线程获得的相同 Job 时才会阻塞)

不知道这个方法能不能做,有没有意义

两个线程正在运行方法内部的以下代码

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 行停止执行,他的状态从 running 更改为 runnable 并设置为在轮询中等待。

JVM 给了 ThreadB 机会,ThreadB 执行了我不希望发生的第 1、2、3、4、5、6 行。我希望在第 2,3 行中输入代码的第一个线程在其他线程中的某个人有机会输入相同的代码之前完成

实现这一点的问题是两个线程正在执行具有不同实例的示例方法,因此同步整个方法将无法工作-我还有在此方法中执行的其他代码,我不希望它同步到
所以有吗我的问题的解决方案另外,如果我使 synchronized(this.class){} 它将失去多线程的好处和意义

4

3 回答 3

1

问题是“currentExecutingJob”被定义为静态,这意味着 ExecuteJob 的所有实例共享该变量的相同“实例”。此外,您在同步块之外设置此变量的值,这意味着每个线程将以不受控制的方式设置它。您的以下同步块应该没有任何实际影响。

鉴于您的示例代码的编写方式,在我看来,您不需要任何静态变量,也不需要任何同步,因为没有跨多个线程共享的资源。

但是,您在代码中的注释表明您希望防止两个线程同时执行同一个作业。您的代码没有实现这一点,因为没有比较正在运行的作业来查看是否正在运行相同的作业,即使有比较,您的 getJobsFromPath() 也需要构造一个作业列表,以便相同的对象实例当两个线程/路径遇到相同的“作业”时,需要重用。

我在你的代码中没有看到任何这些。

于 2013-08-06T12:48:22.163 回答
0

我看到你的代码检查工作的状态,如果它准备好了,我认为这不是一个可行的方法

您可以使用 Callable Interface 而不是 Runnable

这是一个详细的示例,可能会对您有所帮助。

Java 并发

于 2013-08-06T12:46:48.303 回答
0

无法评论,所以我将其作为答案。对不起。

同步(当前执行作业)

将在对象curentExecutingJob 上同步(用您的话来说,内存)。如果使用 currentExecutingJob.equals(otherExecutingJob) == true 在另一个对象 otherExecutingJob 上同步,则两个同步语句不会相互影响。

对于您的问题/问题:如果您描述 getJobsFromPath 正在做什么或应该做什么以及您实际想要做什么以及您的问题实际是什么,这将是有帮助的。这对我来说不是很清楚。

于 2013-08-06T12:43:10.907 回答