2015-06-08 2 views
0

У меня четыре потока выполняется асинхронно, используя CompletableFuture, как показано ниже в коде. и все они должны получить доступ к «growSeedXYList». когда я запускаю код, я не получаю никаких ошибок, но некоторое время я получаю «java.util.concurrent.completionexception» , и я думаю, это потому, что «growSeedXYList» не синхронизирован.Как избежать параллельного доступа к ресурсу?

, пожалуйста, дайте мне знать, как синхронизировать «growSeedXYList»?

обновление:

this.grownSeedXYList is a list that will be populated with some Point objects based on the runnable class used (GrowSeedSERun, GrowSeedNWRun, GrowSeedNERun, GrowSeedSWRun) 

четыре нити запускаются с использованием Compltable будущего

this.grownSeedXYList = new ArrayList<Point>(); 
this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedSERun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor); 
       this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedNWRun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor); 
       this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedNERun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor); 
       this.growSeedFutureList = CompletableFuture.runAsync(new GrowSeedSWRun(this.saliencyMat, this.seedXY, this.seedVal), this.growSeedExecutor); 
       CompletableFuture.allOf(this.growSeedFutureList).join(); 

GrowSeedSERun класс:

private class GrowSeedSERun implements Runnable { 

    private Mat saliencyMat = null; 
    private double seedVal; 
    private Point seedXY = null; 

    public GrowSeedSERun(Mat saliencyMat, Point seedXY, double seedVal) { 
     // TODO Auto-generated constructor stub 
     this.saliencyMat = saliencyMat; 
     this.seedXY = seedXY; 
     this.seedVal = seedVal; 
    } 
    public void run() { 
     // TODO Auto-generated method stub 
     growSeedsSE(this.saliencyMat, this.seedXY, this.seedVal); 
    } 
} 

growSeedsSE:

private void growSeedsSE(Mat saliencyMat, Point seedXY, Double seedVal) { 
    // TODO Auto-generated method stub 
    int origX = (int) seedXY.x; 
    int origY = (int) seedXY.y; 

    if (this.withinRange(saliencyMat.get(origY, ++origX)[0])) { 

     if ((this.grownSeedXYList != null) && (!this.grownSeedXYList.contains(new Point(origX, origY)))) { 

      //Log.D(TAG, "growSeedsSE", "newX: origX: "+origX); 
      //Log.D(TAG, "growSeedsSE", "newX: origY: "+origY); 
      //Log.D(TAG, "growSeedsSE", "newX: value: "+saliencyMat.get(origY, origX)[0]); 

      this.grownSeedXYList.add(new Point(origX, origY)); 

     } else { 
      Log.D(TAG, "growSeedsSE", "point: "+ new Point(origX, origY)+" contained in the list"); 
     } 
     this.growSeedsSE(this.saliencyMat, new Point(origX, origY), this.saliencyMat.get(origY, origX)[0]); 

    } else if (this.withinRange(saliencyMat.get(++origY, (int) this.seedXY.x)[0])) { 
     origX = (int) this.seedXY.x; 

     if ((this.grownSeedXYList != null) && (!this.grownSeedXYList.contains(new Point(origX, origY)))) { 

      //Log.D(TAG, "growSeedsSE", "newY: origX: "+origX); 
      //Log.D(TAG, "growSeedsSE", "newY: origY: "+origY); 
      //Log.D(TAG, "growSeedsSE", "newY: value: "+saliencyMat.get(origY, origX)[0]); 

      this.grownSeedXYList.add(new Point(origX, origY)); 

     } else { 
      Log.D(TAG, "growSeedsSE", "point: "+ new Point(origX, origY)+" contained in the list"); 
     } 
     this.growSeedsSE(this.saliencyMat, new Point(origX, origY), this.saliencyMat.get(origY, origX)[0]); 
    } 
} 
+1

Вы не показали нам, что 'grownSeedXYList 'есть или где он инициализирован или объявлен. Кроме того, если вы получаете «CompletionException», разместите его stacktrace. –

+0

Вы повторно присваиваете 'growSeedFutureList' четыре раза подряд. В чем цель этого? Вы пытаетесь добавить новые 'CompletableFutures' в' List'? –

+0

Итак, это 'ArrayList'. 'ArrayList' не являются потокобезопасными, поэтому, если вы используете один и тот же экземпляр для потоков, у вас проблемы. –

ответ

2

Ваш grownSeedXYList распределяется между нитями. Ваш самый простой вариант будет использовать объявить его следующим образом:

this.grownSeedXYList = Collections.synchronizedList(new ArrayList<Point>()); 

Это заставит grownSeedXYList коллекцию Потокобезопасная. FYI, я считаю, в отсутствие полного walkback для CompletionException, что вы, вероятно, получил его на призыв join, потому что на резьб поймал ConcurrentModificationException

Edit: Как обнаруживаемых с помощью @ user270349 в комментариях ниже и как отмечено javadoc, вам все равно нужно будет синхронизировать по grownSeedXYList, если вы перебираете его. В таком случае, вы могли бы сделать следующее:

synchronized(grownSeedXYList) { 
    Iterator i = grownSeedXYList.iterator(); 
    while (i.hasNext()) 
     foo(i.next()); 
    } 
} 

Однако синхронизация не требуется, если вы используете для/каждого блока, как в:

for (Point point : grownSeedXYList) { 
    foo(point); 
} 
+1

Этого недостаточно, если есть итерации по списку, в то время как другой поток пишет на него. См. Этот вопрос http://stackoverflow.com/questions/15437799/-used-synchronized-list-and-i-still-get-concurrentmodificationexception – aalku

+0

Обратите внимание, что последствия синхронизации с синхронизированной коллекцией связаны с производительностью, но в этом случае это необходимый компромисс из-за параллелизма. Вы просто не хотели бы использовать его в местах, где параллелизм не был проблемой. –

+1

@ user270349 Хорошая точка. @ user2121, похоже, не делает этого в этом случае. Однако, как всегда, полезно отметить такие оговорки! Он также вызывается в JavaDoc для 'Collections.synchronizedList()', btw (http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedList-java.util. Список-). –

1

В Java, используйте блокировку Mutex вокруг ресурса.

Более безопасный замок с флажками поворота можно найти здесь. https://docs.oracle.com/javase/tutorial/essential/concurrency/newlocks.html

import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

public class main { 

    public static void main(String[] args) 
    { 
     final Lock lock = new ReentrantLock(); 

     try { 
      lock.tryLock(); 
     } finally { 
      lock.unlock(); 
     } 
    } 
} 
Смежные вопросы