JavaRush /Java блог /Random UA /Кава-брейк #160. Глибоке занурення Java ThreadLocal. Клас...

Кава-брейк #160. Глибоке занурення Java ThreadLocal. Клас Scanner в Java

Стаття з групи Random UA

Глибоке занурення у Java ThreadLocal

Джерело: Devgenios Сьогодні ви дізнаєтеся про ThreadLocal - один з поширених класів, що використовуються при розробці Java-додатків. Кава-брейк #160.  Глибоке занурення Java ThreadLocal.  Клас Scanner в Java - 1

Що таке ThreadLocal?

Клас ThreadLocal зберігає локальні змінні потоків. Ці змінні ізольовані між різними потоками і можуть бути доступними лише своєму власному потоку. Варіанти застосування ThreadLocal :
  1. Ізоляція даних між потоками.
  2. Управління сесіями для підключення до бази даних.
  3. Зберігання трансакційної інформації потоку.

Як використовувати ThreadLocal?

Давайте розглянемо найпростіший приклад.
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(()-> {
        //Присваиваем значення каждому потоку
        local.set(a+"  "+random.nextInt(100));
        System.out.println("Thread number and its local value  "+ local.get());
    }).start());
}
У наведеному вище коді ми створюємо клас ThreadLocal , створюємо 5 потоків, присвоюємо значення ThreadLocal у кожному потоці та виводимо на друк. При виводі отримуємо: Кава-брейк #160.  Глибоке занурення Java ThreadLocal.  Клас Scanner в Java - 2

Що під капотом?

Якщо уважно подивитися, то можна зрозуміти, що в ThreadLocal з цього прикладу коду є два важливі методи.
  • public T get() {}

  • public void set (T value) {}

Давайте подивимося на метод setter у вихідному коді ThreadLocal :
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
}
Метод setter спочатку отримує поточний потік і викликає метод getMap() отримання класу ThreadLocalMap . Якщо map існує, візьміть поточний потік t як ключ, вхідний параметр як значення та встановіть пару {key:value} у map. Якщо ні, створіть map . Тепер у вас може постати питання - що таке 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 — це внутрішній статичний клас ThreadLocal , що визначає клас Entry для зберігання даних. Entry використовує екземпляр ThreadLocal як ключ і встановлює значення, яке ми передаємо. Якщо на даному етапі це звучить занадто заплутано , просто запам'ятайте, що саме клас Entry ThreadLocalMap виконує фактичне зберігання значень. Щоб отримати дані з ThreadLocal , ми використовуємо метод getter :
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();
}
У методі getter ми будемо використовувати currentThread як ключ для отримання ThreadLocalMap . Потім map отримає getEntry() на основі екземпляра ThreadLocal і поверне екземпляр Entry , а потім збережене значення. Ось схема, яка допоможе розібратися: Кава-брейк #160.  Глибоке занурення Java ThreadLocal.  Клас Scanner в Java - 3Кава-брейк #160.  Глибоке занурення Java ThreadLocal.  Клас Scanner в Java - 4
  1. Кожен потік підтримує посилання ThreadLocalMap .

  2. ThreadLocalMap є внутрішнім статичним класом ThreadLocal та використовує клас Entry для зберігання.

  3. Ключ ThreadLocalMap є екземпляром ThreadLocal і може мати декілька ThreadLocal .

  4. Сам ThreadLocal не зберігає значення, але це ключ для потоку, який допоможе отримати значення ThreadLocalMap .

Зверніть увагу, що краще видалити ThreadLocal , щоб уникнути OOM (Out-of-Memory Error, помилка нестачі пам'яті) через "слабке" посилання в класі Entry .

Клас Scanner в Java

Джерело: Medium Ця публікація допоможе вам ознайомитися з класом Scanner у Java. Кава-брейк #160.  Глибоке занурення Java ThreadLocal.  Клас Scanner в Java - 5Клас Scanner Java — це клас, який ми використовуємо, коли хочемо отримати значення від користувача. Розібратися в ньому найлегше на прикладах, тому давайте розберемо його більш наочно. Створення класу Scanner – це один із трьох кроків, які ми робимо, щоб отримати значення від користувача. Перший крок — створити об'єкт із класу сканера.
Scanner scan=new Scanner(System.in);
Тепер ми маємо об'єкт сканера. Цей об'єкт матиме властивості Scanner із класу Scanner . Після першого кроку користувач може ввести бажане значення, але якщо ми не направимо користувача і не відобразимо значення в консолі або в додатку, це буде не дуже добре з точки зору зручності. Тому краще поінформувати та направити користувача:
System.out.println("Please enter your name");
String name=scan.next();
System.out.println("Your Name:"+name);
У першому рядку ми запитуємо користувача, що ми хочемо. Насправді це не має нічого спільного зі сканером, але завжди корисно підказувати своїм користувачам. У другому рядку ми надамо значення, яке користувач введе в дані, і збережемо його, щоб ми могли використовувати його пізніше. В останньому рядку ми бачимо, що можемо використовувати отримане від користувача значення на власний розсуд. Давайте додамо до нашого коду ще кілька деталей:
System.out.println("Please enter your last name");

String lastName=scan.next();

System.out.println("Your Name " + name + " " + "Your Last Name" + lastName);
Власне кажучи, ми повторабо два попередні рядки, запитабо значення у користувача і зберегли його. Тепер у останньому рядку ми використовували два значення, які взяли у користувача, і які тепер використовуються разом.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ