Cześć,
dawno niczego nie pisałem tutaj, niestety czas nie pozwala mi prowadzić tego bloga tak systematycznie jakbym chciał. Dziś jednak znalazło się trochę czasu między pisaniem pracy inż, pracą, dziewczyną i życiem – co zaowocowało takim oto, krótkim wpisem.
Zajmiemy się dziś wzorcem ThreadLocal, czyli rozwiązaniem problemu, kiedy to chcemy aby jakaś zmienna udostępniała swoją kopię każdemu wątkowi który o nią zapyta.
Spójrzmy na taki scenariusz:
Mamy klasę o nazwie VariableContainer. Zawiera ona jedno pole typu int o nazwie variable. Jest to pole statyczne, gdyż chcemy aby odnosił się on do typu a nie konkretnego obiektu. I takiej konstrukcji używamy w naszym projekcie.
Teraz zdarza się jakiś case, gdzie musimy podzielić naszą aplikację na wątki. A więc n wątków będzie pracować na naszej zmiennej. Niestety podczas pisania tego kodu, okazuje się że każdy wątek powinien mieć w swojej pamięci lokalnej kopię naszej zmiennej variable i dopiero na niej pracować… Jak to rozwiązać? Zerknijmy pierw na kod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class VariableContainer { public static void main(String args[]) { for(int i=0;i<20;i++) { NamedThread nt = new NamedThread(i); nt.start(); } System.out.println("Main: "+VariableContainer.get()); } public VariableContainer() { } private static int variable = 0; public static void increaseBy(int howMuch){ variable+=howMuch; } public static int get(){ return variable; } } |
gdzie NamedThread to klasa dziedzicząc po wątku, symuluje ona pracę na zmiennej variable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public class NamedThread extends Thread { private int number; public NamedThread(int number) { this.number=number; } @Override public void run() { VariableContainer.increaseBy(4); System.out.println("Value for thread nr."+number+" is:"+VariableContainer.get()); } } |
Kod taki jak wyżej oczywiście daje na wyjściu bzdury:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Value for thread nr.1 is:4 Value for thread nr.2 is:12 Value for thread nr.0 is:8 Value for thread nr.5 is:16 Value for thread nr.3 is:24 Value for thread nr.6 is:24 Main: 36 Value for thread nr.17 is:40 Value for thread nr.13 is:36 Value for thread nr.10 is:44 Value for thread nr.9 is:32 Value for thread nr.14 is:48 Value for thread nr.18 is:52 Value for thread nr.4 is:52 Value for thread nr.7 is:56 Value for thread nr.8 is:60 Value for thread nr.11 is:64 Value for thread nr.12 is:68 Value for thread nr.15 is:72 Value for thread nr.16 is:76 Value for thread nr.19 is:80 |
To co widzimy jest wielce dalekie od zamierzonego efektu. Chcielibyśmy aby wartość zmiennej variable nie była dzielona pomiędzy wątki.
Możemy do tego użyć wzorca ThreadLocal. Istnieje klasa opakowująca o tej samej nazwie w Javie. Możemy użyć jej w taki sposób:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class VariableContainer { public static void main(String args[]) { for(int i=0;i<20;i++) { NamedThread nt = new NamedThread(i); nt.start(); } System.out.println("Main: "+VariableContainer.get()); } private static ThreadLocal<Integer> variable = new ThreadLocal<Integer>(){ @Override protected Integer initialValue(){ return 0; } }; public static void increaseBy(int howMuch){ variable.set( variable.get()+howMuch ); } public static int get(){ return variable.get(); } } |
Dzieki takiej zmianie kodu, wyjście prezentuje się znaczenie poprawniej:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | Value for thread nr.1 is:4 Value for thread nr.5 is:4 Value for thread nr.9 is:4 Value for thread nr.2 is:4 Value for thread nr.13 is:4 Value for thread nr.6 is:4 Value for thread nr.17 is:4 Main: 0 Value for thread nr.10 is:4 Value for thread nr.0 is:4 Value for thread nr.14 is:4 Value for thread nr.18 is:4 Value for thread nr.3 is:4 Value for thread nr.4 is:4 Value for thread nr.7 is:4 Value for thread nr.8 is:4 Value for thread nr.11 is:4 Value for thread nr.12 is:4 Value for thread nr.15 is:4 Value for thread nr.16 is:4 Value for thread nr.19 is:4 |
Jak widać, teraz zmienna wartość zmiennej variable jest dzielona między wątki, zachowujemy wartość odpowiednią dla wątku głównego oraz dajemy, każdemu innemu, swoją własną kopię wartości tej zmiennej.
Warto znać takie zastosowania, czasem się przydają ;)
Pozdrawiam,
Mateusz M.
Cześć. Dziś luźny artykuł, bo dziś pobawimy się jedną z pierwszy wersji Pythona. Skompilujemy go i zobaczymy co tam w… Read More
Nowy rok czas zacząć! Więc lećmy z podsumowaniem. Nowy artykuł Nie uwierzycie, ale pojawił się na blogu nowy artykuł! Piszę… Read More
Cześć! W Pythonie 3.13 dodano JITa! JIT, czyli just-in-time compiler to optymalizacja na która Python naprawdę długo czekał. Na nasze… Read More
Cześć! Zapraszam na podsumowanie roku 2024. Książki W sumie rok 2024 był pod względem ilości książek nieco podobny do roku… Read More
Podtrzymując tradycję, prawie regularnych podsumowań, zapraszam na wpis! Nie mogło obyć się bez Karkonoszy We wrześniu odwiedziłem z kolegą Karkonosze,… Read More
Oj daaawnoo mnie tu nie było. Ale wakacje to był czas dużej liczby intensywnych wyjazdów i tak naprawdę, dopiero jakoś… Read More