2012-11-28 12 views
13

Podczas korzystania z wielu wątków nauczyłem się używać zmiennych statycznych, gdy chcę korzystać z licznika, do którego dostęp uzyska wiele wątków.Java - używanie AtomicInteger vs Static int

przykład:

static int count=0; Później w programie go używać jako count++;.

Dzisiaj natknąłem się na coś o nazwie AtomicInteger i dowiedziałem się również, że jest bezpieczne dla wątków i można użyć jednej z jego metod o nazwie getAndInrement(), aby osiągnąć ten sam efekt.

Czy ktoś może mi pomóc zrozumieć, jak używać static atomicInteger kontra static int count?

+0

trzeba chronić jednoczesnych dostępów do obiekt 'int' siebie. Ale 'AtomicInteger' został zaprojektowany tak, aby był bezpieczny dla wątków. – reprogrammer

+9

'static' nie ma nic wspólnego z multi-threading. –

+0

O ile mi wiadomo, używamy zmienne lotne zamiast zmiennych statycznych w środowiskach wielowątkowych. – Vishal

Odpowiedz

20

-AtomicInteger służy do wykonywania operacji atomowej nad całkowitą, jego alternatywa, jeśli nie chcesz używać synchronized słowa kluczowego.

- Korzystanie z volatile na polu dla Atomowej da niespójne wyniki.

int volatile count; 

public void inc(){ 

count++ 

} 

-static dokona zmiennej współdzielonej przez wszystkie instancje tej klasy, Ale nadal będzie produkować niespójne wyniki w wielowątkowości środowiska.

Więc spróbuj tych, kiedy jesteś w środowisku wielowątkowość:

1. Jego zawsze lepiej śledzić Briana zasada:

Gdy kiedykolwiek piszemy zmienną, która jest obok odczytuje przez inny wątek lub gdy czytamy zmienną, która jest napisana po prostu przez inny wątek, musi zostać zsynchronizowana. Współużytkowane pola muszą być ustawione jako prywatne, co spowoduje synchronizację metod odczytu i zapisu/zestawień atomowych .

2. Drugą opcją jest użycie Atomic Classes, jak AtomicInteger, AtomicLong, AtomicReference, etc.

+0

Dzięki Kumar !!!!! – user547453

+0

@ user547453 Serdecznie zapraszamy ........... –

1

Z AtomicInteger z gwarancją incrementAndGet() na atomową.
Jeśli użyjesz count++, aby uzyskać poprzednią wartość, nie ma gwarancji, że jest atomowe.


Coś, co przegapiłem z twojego pytania - i stwierdzono inną odpowiedzią - static nie ma nic wspólnego z wątkami.

+0

co masz na myśli mówiąc "atomowy"? – user547453

+2

Zobacz http://en.wikipedia.org/wiki/Atomicity_(programming) – reprogrammer

+1

oznacza to na przykład, że jeśli dwa wątki używają, na przykład 'prevCount = count ++ 'w tym samym czasie, może to być, że oba wątek otrzyma taką samą wartość prevCount. –

1

"Statyczny" powoduje, że var jest poziomem klas. Oznacza to, że jeśli zdefiniujesz "static int count" w klasie, bez względu na to, ile instancji stworzyłeś, wszystkie instancje używają tego samego "count". Chociaż AtomicInteger jest normalną klasą, to po prostu dodaje ochronę synchronizacji.

1

static int counter nie daje wynik niezgodny z multithreaded środowiska, chyba że zrobić licznik volatile lub zrobić blok przyrost synchronized.

W przypadku automic daje lock-freeprogramowanie pojedynczych zmiennych.

Więcej szczegółów w automic's i link

+1

Nie sądzę, że lotny jest wystarczający, aby ++ było bezpieczne. –

1

myślę nie ma gwarancyjny zobaczyć na count++ najnowszy wartości. count++ musi odczytać wartość count. Inny Thread mógł napisać nową wartość do count, ale zachował swoją wartość na lokalnej pamięci podręcznej Thread, i. mi. nie spłukuje się do pamięci głównej. Również twój Thread, który czyta count, nie ma gwarancji odczytu z pamięci głównej, i. mi. odśwież z pamięci głównej. synchronize gwarantuje to.

+0

Dzięki Vertex !!!!! – user547453

1

AtomicInteger ma sprawić, by przyrost i przyrost był procesem atomowym. Może być uważany za sekwenser w bazie danych. Dostarcza metody narzędziowe do zwiększania, zmniejszania wartości delta int.

static int może spowodować problem, jeśli otrzymujesz licznik, a następnie przetwarzanie, a następnie aktualizowanie. AtomicInteger robi to łatwo, ale nie możesz go użyć, jeśli musisz zaktualizować licznik na podstawie wyników przetwarzania.

+0

Dzięki Pankaj !!!!! – user547453

5

Zgadzam się z @ odpowiedzi Kumara.

Niestabilność nie jest wystarczająca - ma pewne implikacje dla kolejności w pamięci, ale nie zapewnia atomowości ++.

Naprawdę trudną rzeczą w programowaniu wielowątkowym jest to, że problemy mogą nie pojawić się w rozsądnej ilości testów. Napisałem program do zademonstrowania problemu, ale ma wątki, które nie robią nic poza licznikami przyrostu. Mimo to liczba ta wynosi około 1% prawidłowej odpowiedzi. W prawdziwym programie, w którym wątki mają inne zadanie do wykonania, może istnieć bardzo małe prawdopodobieństwo, że dwa wątki wykonają ++ wystarczająco blisko, aby jednocześnie pokazać problem. Poprawności wielowątkowości nie można przetestować, należy ją zaprojektować.

Ten program wykonuje to samo zadanie zliczania, używając prostego statycznego int, lotnego int i AtomicInteger. Tylko AtomicInteger konsekwentnie otrzymuje właściwą odpowiedź. Typowa moc na wieloprocesorowych z 4 podwójnymi rdzenie to:

count: 1981788 volatileCount: 1982139 atomicCount: 2000000 Expected count: 2000000 

Oto kod źródłowy:

import java.util.ArrayList; 
    import java.util.List; 
    import java.util.concurrent.atomic.AtomicInteger; 

    public class Test { 
    private static int COUNTS_PER_THREAD = 1000000; 
    private static int THREADS = 2; 

    private static int count = 0; 
    private static volatile int volatileCount = 0; 
    private static AtomicInteger atomicCount = new AtomicInteger(); 

    public static void main(String[] args) throws InterruptedException { 
     List<Thread> threads = new ArrayList<Thread>(THREADS); 
     for (int i = 0; i < THREADS; i++) { 
     threads.add(new Thread(new Counter())); 
     } 
     for (Thread t : threads) { 
     t.start(); 
     } 
     for (Thread t : threads) { 
     t.join(); 
     } 
     System.out.println("count: " + count + " volatileCount: " + volatileCount + " atomicCount: " 
      + atomicCount + " Expected count: " 
      + (THREADS * COUNTS_PER_THREAD)); 
    } 

    private static class Counter implements Runnable { 
     @Override 
     public void run() { 
     for (int i = 0; i < COUNTS_PER_THREAD; i++) { 
      count++; 
      volatileCount++; 
      atomicCount.incrementAndGet(); 
     } 
     } 
    } 
    } 
+0

Dzięki Patricia ... Rozumiem użycie atomicInteger, kiedy muszę użyć licznika wskazanego w moim oryginalnym pytaniu. Ale co jeśli mam 3 zsynchronizowane wątki aktualizujące wartości zmiennych, takie jak ThreadA, ThreadB i ThreadC (na przykład). W tym przypadku (jak zasugerował Kumar), muszę użyć prywatnej metody synchronizowanej, aby odczytać i zapisać wartość. Zmienię też moją zmienną na "Static Volatile". Przykład: 'private volatile static String threadName =" ThreadX ";' – user547453

+0

@ user547453 Jeśli wszystkie odwołania do zmiennej są zsynchronizowane z tym samym obiektem, nie ma potrzeby, aby była ona niestabilna. Może to spowodować brak efektu lub spowolnić niepotrzebny kod. Istnieje wiele sposobów na udostępnienie zmiennej między wieloma wątkami - nie musi ona być statyczna. –

+0

Jedna ważna rzecz do zapamiętania: '++' nie jest operacją atomową - jest skrótem dla 'a = a + 1', która polega na odczytywaniu wartości i zapisywaniu wartości. Jednak odczytanie lub ustawienie wartości jest operacją atomową na zmiennym polu. – mucaho