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.
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
Cześć! Zapraszam na krótkie podsumowanie kwietnia. Wyjazd do Niemiec A dokładniej pod granicę z Francją. Chrześnica miała pierwszą komunię. Po… Read More
Ostatnio tygodnie były tak bardzo wypełnione, że nie udało mi się napisać nawet krótkiego podsumowanie. Więc dziś zbiorczo podsumuję luty… Read More
Zapraszam na krótkie podsumowanie miesiąca. Książki W styczniu przeczytałem "Homo Deus: Historia jutra". Książka łudząco podoba do wcześniejszej książki tego… Read More
Cześć! Zapraszam na podsumowanie roku 2023. Książki Zacznijmy od książek. W tym roku cel 35 książek nie został osiągnięty. Niemniej… Read More
Zapraszam na krótkie podsumowanie miesiąca. Książki W grudniu skończyłem czytać Mein Kampf. Nudna książka. Ciekawsze fragmenty można by było streścić… Read More