2009-07-15 15 views
20

Czy są jakieś problemy dotyczące współbieżności z jednym wątkiem odczytu z jednego indeksu tablicy, podczas gdy inny wątek zapisuje do innego indeksu tablicy, o ile indeksy są różne?java array thread-safety

np. (Ten przykład nie koniecznie zalecany do rzeczywistego użytkowania, tylko zilustrować mój punkt widzenia)

class Test1 
{ 
    static final private int N = 4096; 
    final private int[] x = new int[N]; 
    final private AtomicInteger nwritten = new AtomicInteger(0); 
    // invariant: 
    // all values x[i] where 0 <= i < nwritten.get() are immutable 

    // read() is not synchronized since we want it to be fast 
    int read(int index) { 
     if (index >= nwritten.get()) 
      throw new IllegalArgumentException(); 
     return x[index]; 
    } 
    // write() is synchronized to handle multiple writers 
    // (using compare-and-set techniques to avoid blocking algorithms 
    // is nontrivial) 
    synchronized void write(int x_i) { 
     int index = nwriting.get(); 
     if (index >= N) 
      throw SomeExceptionThatIndicatesArrayIsFull(); 
     x[index] = x_i; 
     // from this point forward, x[index] is fixed in stone 
     nwriting.set(index+1); 
    }  
} 

edit: krytyce ten przykład nie jest moja sprawa, ja dosłownie po prostu chcesz wiedzieć, czy tablicową dostęp do jednego indeksu, równolegle do dostęp do innego indeksu, stwarza problemy współbieżności, nie mógł wymyślić prostego przykładu.

Odpowiedz

12

ile nie dostaniesz nieprawidłowy stan zmieniając tablice jak wspomniałeś, będziesz mieć ten sam problem, który występuje, gdy dwa wątki oglądają nieulotną liczbę całkowitą bez synchronizacji (zobacz sekcję w samouczku Java pod numerem Memory Consistency Errors). Zasadniczo problem polega na tym, że wątek 1 może zapisywać wartość w przestrzeni i, ale nie ma gwarancji, kiedy (lub jeśli) wątek 2 zobaczy zmianę.

Klasa java.util.concurrent.atomic.AtomicIntegerArray robi to, co chcesz zrobić.

+0

dzięki ... drat, chciałem użyć tablicy byte [] i wygląda na to, że nie ma takiego zwierzęcia atomowego .... Myślę, że po prostu użyję zsynchronizowanych metod i utrzymam to w prostocie. –

+2

Jeśli masz dużo więcej odczytów niż zapisów, możesz zajrzeć do java.util.concurrent.locks.ReadWriteLock –

+0

huh, interesujący ... –

4

Ten przykład ma wiele rzeczy, które różnią się od prozy.

Odpowiedź na to pytanie jest taka, że ​​różne elementy tablicy są dostępne niezależnie, więc nie potrzebujesz synchronizacji, jeśli dwa wątki zmieniają różne elementy.

Jednak model pamięci Java nie daje żadnych gwarancji (o których mi wiadomo), że wartość zapisana przez jeden wątek będzie widoczna dla innego wątku, chyba że zsynchronizujesz dostęp.

W zależności od tego, co naprawdę chcesz osiągnąć, prawdopodobnie już java.util.concurrent ma klasę, która zrobi to za Ciebie. A jeśli nie, nadal polecam przyjrzenie się kodowi źródłowemu dla ConcurrentHashMap, ponieważ wydaje się, że twój kod robi to samo, co robi zarządzanie tablicą haszującą.

1

Nie jestem naprawdę pewien, czy synchronizacja tylko metoda unsychronizedbędzie działać. Nie do końca są to wszystkie konsekwencje, ale przynajmniej może to prowadzić do tego, że metoda zwraca pewne wartości, które zostały właśnie przesłonięte przez write.

1

Tak, ponieważ złe przeplatanie pamięci podręcznej może nadal występować w środowisku z wieloma procesorami/rdzeniami. Istnieje kilka opcji, aby uniknąć go:

  • Użyj Niebezpieczne Sun-prywatnej biblioteki do atomowo ustawić element w tablicy (lub jsr166y dodana funkcja w Java7
  • Zastosowanie AtomicXYZ [] tablica
  • Wykorzystanie niestandardowych obiekt z jednej lotnej dziedzinie i mają tablicę tego obiektu.
  • Użyj ParallelArray z jsr166y aneksu zamiast w swoim algorytmie
1

od read() nie jest zsynchronizowany można mieć następujący scen Ario:

Thread A enters write() method 
Thread A writes to nwriting = 0; 
Thread B reads from nwriting =0; 
Thread A increments nwriting. nwriting=1 
Thread A exits write(); 

Ponieważ chcesz, aby zagwarantować, że zmienne adresy nigdy konflikt, co o czymś takim (dyskontowanie problemy indeks tablicy):

int i; 
synchronized int curr(){ return i; } 
synchronized int next(){ return ++i;} 

int read() { 
     return values[curr()]; 
    } 

void write(int x){ 
    values[next()]=x; 
} 
+0

dziękuję, ale nie moje pytanie i twój scenariusz nie może się zdarzyć (kroki 2 i 3 nigdy nie pojawią się) –