Zanurz się głęboko w Java ThreadLocal
Źródło: Devgenios Dzisiaj dowiesz się o ThreadLocal, jednej z powszechnych klas używanych przy tworzeniu aplikacji Java.Co to jest ThreadLocal?
Klasa ThreadLocal przechowuje zmienne lokalne dla wątków. Zmienne te są izolowane między różnymi wątkami i można uzyskać do nich dostęp tylko za pośrednictwem ich własnego wątku. Przypadki użycia ThreadLocal :- Izoluj dane między wątkami.
- Zarządzanie sesjami dla połączeń z bazami danych.
- Przechowywanie informacji o transakcjach wątku.
Jak korzystać z ThreadLocal?
Spójrzmy na prosty przykład.public static void main(String[] args) {
//Создаем ThreadLocal
ThreadLocal<String> local = new ThreadLocal<>();
//Создаем новый класс Random
Random random = new Random();
//Создаем 5 потоков
IntStream.range(0, 5).forEach(a-> new Thread(()-> {
//Присваиваем oznaczający каждому потоку
local.set(a+" "+random.nextInt(100));
System.out.println("Thread number and its local value "+ local.get());
}).start());
}
W powyższym kodzie tworzymy klasę ThreadLocal , tworzymy 5 wątków, przypisujemy wartość do ThreadLocal w każdym wątku i drukujemy. Podczas wyprowadzania otrzymujemy:
Co kryje się pod maską?
Jeśli przyjrzysz się uważnie, zobaczysz, że w ThreadLocal istnieją dwie ważne metody z tego przykładowego kodu.-
publiczny T get() {}
-
publiczny zestaw pustych wartości (wartość T) {}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
Metoda setter najpierw pobiera bieżący wątek i wywołuje metodę getMap() w celu pobrania klasy ThreadLocalMap . Jeśli mapa istnieje, przyjmij bieżący strumień t jako klucz, parametr wejściowy jako wartość i ustaw parę {klucz:wartość} na map. Jeśli nie, utwórz mapę . Teraz możesz mieć pytanie - co to jest ThreadLocalMap ?
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
ThreadLocalMap to wewnętrzna klasa statyczna w ThreadLocal , która definiuje klasę Entry do przechowywania danych. Entry używa instancji ThreadLocal jako klucza i ustawia wartość, którą przekazujemy. Jeśli w tym momencie brzmi to zbyt zagmatwanie, pamiętaj, że to klasa Entry w ThreadLocalMap faktycznie przechowuje wartości. Aby pobrać dane z ThreadLocal, używamy metody gettera :
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
W metodzie gettera użyjemy currentThread jako klucza do pobrania ThreadLocalMap . Następnie map wykona funkcję getEntry() w oparciu o instancję ThreadLocal i zwróci instancję Entry , a następnie zapisaną wartość. Oto diagram, który pomoże Ci to rozgryźć:
-
Każdy wątek utrzymuje odwołanie do ThreadLocalMap .
-
ThreadLocalMap jest wewnętrzną klasą statyczną ThreadLocal i używa klasy Entry do przechowywania.
-
Klucz ThreadLocalMap jest instancją ThreadLocal i może mieć wiele ThreadLocals .
-
Sam ThreadLocal nie przechowuje wartości, ale jest kluczem dla wątku, który pomoże uzyskać wartość z ThreadLocalMap .
Klasa skanera w Javie
Źródło: Medium Ten post pomoże Ci zapoznać się z klasą Scanner w Javie. Klasa Scanner w Javie to klasa, której używamy, gdy chcemy uzyskać wartość od użytkownika. Najłatwiej to zrozumieć na przykładach, więc spójrzmy na to jaśniej. Utworzenie klasy Scanner to jeden z trzech kroków, jakie wykonujemy, aby uzyskać wartość od użytkownika. Pierwszym krokiem jest utworzenie obiektu z klasy skanera.Scanner scan=new Scanner(System.in);
Teraz mamy obiekt skanera. Obiekt ten będzie miał właściwości Scanner z klasy Scanner . Już po pierwszym kroku użytkownik może wprowadzić żądaną wartość, jednak jeśli nie poprowadzimy użytkownika i nie wyświetlimy wartości w konsoli lub w aplikacji, nie będzie to zbyt dobre pod względem użyteczności. Dlatego lepiej poinformować i poinstruować użytkownika:
System.out.println("Please enter your name");
String name=scan.next();
System.out.println("Your Name:"+name);
W pierwszej linijce pytamy użytkownika, czego od niego chcemy. Właściwie nie ma to nic wspólnego ze skanerem, ale zawsze dobrze jest dać wskazówki użytkownikom. W drugiej linii przypiszemy wartość, którą użytkownik wprowadzi do danych i zapiszemy ją, abyśmy mogli z niej później skorzystać. W ostatniej linijce widzimy, że otrzymaną od użytkownika wartość możemy wykorzystać według własnego uznania. Dodajmy jeszcze kilka szczegółów do naszego kodu:
System.out.println("Please enter your last name");
String lastName=scan.next();
System.out.println("Your Name " + name + " " + "Your Last Name" + lastName);
Zasadniczo powtórzyliśmy dwie poprzednie linie, zapytaliśmy użytkownika o wartość i zapisaliśmy ją. Teraz w ostatniej linii użyliśmy dwóch wartości, które pobraliśmy od użytkownika i które teraz są używane razem.
GO TO FULL VERSION