1

I'm implementing a program that calculates a Julia set. It will use multiple threads, depending on how many processors are available. Each thread calculates a line, but only when that line is not being calculated by another thread. This part WORKS pretty well.

But sometimes when I test it with bigger images (more lines to calculate, for example instead of getHeight() = 1200, I set it to 3000, there are some lines which are skipped). I want to make it more secure, so that no line will be calculated twice, and no lines will be skipped. Here is the code of the run() method:

 public void run() {
     while (counter < getHeight()-1) {  
         synchronized(this) {
             if (counter >= getHeight() -1) { //so that the last line will not be calculated >2 times.
                 return;
             }
             counter++;
             image.setRGB(0, counter, getWidth(), 1, renderLine(counter), 0, 0);
         }
     }
  }

I want it to work like that: if the current line is being calculated, the thread goes to the next line.. without that it get confused, so that lines get skipped..

I'm trying this actually:

 public void run() {
     while (counter < getHeight()-1 && !working) {  
         synchronized(this) {
             working = true;
             if (counter >= getHeight() -1) { //so that the last line will not be calculated >2 times.
                 return;
             }
             counter++;
             image.setRGB(0, counter, getWidth(), 1, renderLine(counter), 0, 0);
             working = false;
         }
     }
  }

but I don't know if it will prevent access to another thread, while a thread is already working, and it will change the value of "counter", meaning that lines can be skipped!

Do I need a boolean variable to notify that a thread is actually working on a line? Any advice?

4

2 回答 2

5

几乎可以肯定,您自己的线程管理做了太多事情。使用 anExecutorService在多个线程之间分配工作而不会重复。

 ExecutorService service = Executors.newFixedThreadPool(
   Runtime.getRuntime().availableProcessors());
 for (int row = minRow; row <= maxRow; row++) {
   service.submit(new FillThisRowRunnable(row));
 }
于 2012-06-05T19:30:41.570 回答
1

您确实需要为所有线程提供一个共享对象。该对象将告诉其他线程要处理哪一行。

我无法确定你现在拥有什么,但似乎每个人synchronized都在不同的情况下,你失去了所有的相互排斥。请记住,当同步发生在共享对象上时,同步仅适用于多个线程,否则每个线程将在没有实现任何目标的线程本地对象上同步。

这是一个例子

public class SharedLineCounter{
   private final int maxNumberOfLines;
   private int currentLineNumber =0;
   public SharedLineCounter(int maxNumberOfLines){
      this.maxNumberOfLines = maxNumberOfLines;
   } 
   public synchronized int getNextLine(){
      if(++currentLineNumber > maxNumberOfLines)
         return -1; //end case
      return currentLineNumber ;
   }
}

public class WorkerThread extends Thread{
    private final SharedLineCounter counter;
    public WorkerThread(SharedLineCounter counter){
       this.counter = counter;
    }
    public void run(){
      int next = -1;
      while((next = counter.getNextLine()) >= 0){
        image.setRGB(0, next , getWidth(), 1, renderLine(next ), 0, 0);
      }
    }
  }
}

在这里,每个线程都将共享这个线程安全行计数器,因此每个线程应该始终获得一个唯一且连续的行号。

编辑以回答您的问题:

您可以通过共享全局实例使线程匿名

public static void main(String args[]){
    final SharedCounter counter = new SharedCounter();

    Thread worker1 = new Thread(new Runnable(){
       public void run(){
            counter.getNextLine(); //etc
       }
    });
    Thread worker2 = new Thread(new Runnable(){
       public void run(){
            counter.getNextLine(); //etc
       }
    });

}

根据您的评论提出一个警告。您应该传入并创建一个匿名可运行文件,子类化和覆盖的方法是new Runnable不好的做法runThread

于 2012-06-05T20:13:16.057 回答