JavaRush /Java блог /Random /Кофе-брейк #252. В чем различие между Thread Local и Virt...

Кофе-брейк #252. В чем различие между Thread Local и Virtual Thread в Java. Как избежать исключения NullPointerException в Java

Статья из группы Random

В чем различие между Thread Local и Virtual Thread в Java

Источник: Medium Это руководство поможет вам лучше понять о концепциях программирования Thread Local (локального потока) и Virtual Thread (виртуального потока). Вы узнаете о различиях между ними и ознакомитесь с несколькими примерами кода. Кофе-брейк #252. В чем различие между Thread Local и Virtual Thread в Java. Как избежать исключения NullPointerException в Java - 1Многопоточность — это фундаментальная концепция программирования на Java, которая позволяет одновременное выполнение задач. Благодаря ей разработчики могут применять возможности параллелизма и повышать производительность своих приложений. В Java существуют две важные функции потоковой обработки — это Thread Local (локальный поток) и Virtual Thread (виртуальный поток).

Понимание Thread Local

Thread Local — это механизм в Java, который позволяет создавать переменные, специфические для каждого потока выполнения. Он обеспечивает способ хранения данных, доступных только для определенного потока, обеспечивая безопасность потоков и избегая взаимодействия данных между несколькими потоками. Каждый поток, обращающийся к локальной переменной потока, имеет свою собственную независимую копию переменной, изолированную от других потоков. Пример Thread Local:

public class ThreadLocalExample {
    public static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            threadLocal.set(10);
            System.out.println("Thread 1: " + threadLocal.get());
            threadLocal.remove();
        });

        Thread thread2 = new Thread(() -> {
            threadLocal.set(20);
            System.out.println("Thread 2: " + threadLocal.get());
            threadLocal.remove();
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();
    }
}
В данном примере мы создаем локальную переменную потока threadLocal типа Integer. Каждый поток устанавливает определенное значение локальной переменной потока с помощью метода set(), а затем извлекает значение с помощью метода get(). Метод remove() вызывается для очистки локальной переменной потока после ее использования. Выполнение этого примера продемонстрирует, что каждый поток работает со своей собственной независимой копией локальной переменной потока.

Понимание Virtual Thread

Virtual Thread — это новая функция, представленная в Java 16 как часть Project Loom. Она представляет собой облегченную альтернативу традиционным потокам, которая более масштабируемая и занимает значительно меньше памяти. Виртуальные потоки управляются виртуальной машиной Java (JVM) и обеспечивают массовое параллельное выполнение без дополнительных расходов на системные ресурсы. Пример Virtual Thread:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class VirtualThreadExample {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newVirtualThreadExecutor();

        executorService.submit(() -> {
            System.out.println("Virtual Thread executing task");
        });

        executorService.shutdown();
    }
}
В приведенном выше примере мы используем класс Executors для создания ExecutorService, специально разработанного для Virtual Threads с помощью метода newVirtualThreadExecutor(). Мы отправляем задачу, представленную лямбда-выражением, в службу-исполнитель для выполнения. Метод shutdown() вызывается для корректного закрытия службы-исполнителя.

Разница между Thread Local и Virtual Thread

  1. Предназначение: Thread Local используется для предоставления переменных, специфичных для потока, что обеспечивает безопасность потока и позволяет избежать вмешательства в данные. С другой стороны, Virtual Thread, представляет собой облегченную альтернативу традиционным потокам, предлагая преимущество в масштабируемости и производительности.
  2. Изоляция переменных: Thread Local предоставляет каждому потоку собственную независимую копию переменной, изолированную от других потоков. Virtual Thread, будучи потоковой моделью, не имеют прямого отношения к переменным, специфичным для потока.
  3. Использование ресурсов: Thread Local фокусируется на управлении данными, относящимися к потоку, а Virtual Thread фокусируется на эффективном использовании системных ресурсов.

Заключение

Thread Local и Virtual Thread — это две разные функции в Java, которые служат разным целям в многопоточном программировании. Thread Local предоставляет механизм для хранения переменных, специфичных для потока, что обеспечивает безопасность потока. Virtual Thread, представленный в Project Loom, предлагает облегченную и хорошо масштабируемую модель многопоточности, которая максимально эффективно использует ресурсы. Понимание различий между Thread Local и Virtual Thread потоком позволяет разработчикам использовать соответствующую функцию в зависимости от их конкретных потребностей и требований в параллельных приложениях Java.

Как избежать исключения NullPointerException в Java

Источник: Medium Изучив эту публикацию, вы узнаете, что такое исключение NullPointerException и как избежать его появления в вашем коде Java. Всякий раз, когда мы пишем код Java, мы всегда должны заботиться о том, чтобы в нем не возникло исключение NullPointerException. Но сначала давайте поговорим о том, что же это за исключение. Предположим, у нас есть класс Student:

@Data
public class Student{
private Integer rollNumber;
private String name;
private String address;
 }
Нам нужно получить определенные данные из класса Student, такие как его rollNumber или name. Давайте представим, что объекты Student имеют значение null, и мы извлекаем значение из нулевого значения вместо допустимого объекта Student.

Student student=fetchStudentDetails(rollNumber);  // вернет student или null
String studentName =student.getName(); // здесь возникнет проблема
Таким образом, у нас есть метод с именем fetchStudentDetails(rollNumber), который вернет нам объект Student. Если же он не будет найден, то метод вернет null в следующей строке, которую мы видим из объекта Student. Он в нашем случае считается нулевым. Если же из него мы попытаемся извлечь name, то в конечном итоге код не будет выполнен и появится исключение NullPointerException. Давайте решим эту проблему так, что даже если student.getName() будет вызван, то он не будет генерировать никаких исключений, а будет хранить null в studentName. Этот вариант намного лучше по сравнению с исключением.

public class Util{
public static <T> Optional<T> T resolveNull(Supplier<T> supplier){
    try{
    T value= supplier.get();
    return Optional.offNullable(value);
    }
    catch(NullPointerException exception){
    // логируем исключение
    }
    return Optional.empty();
}
public static <T> T fetchValue(Supplier<T> supplier){
  return resolveNull(()->supplier.get()).orElse(null);
  }
}
В примере выше мы создали отдельное имя класса Util с методом fetchValue(Supplier<T> supplier). Он нам нужен,чтобы избежать исключения NullPointerException. Давайте посмотрим, как мы можем все это использовать:

@Data
public class Student{
private Integer rollNumber;
private String name;
private String address;
 }
-----------------------------------------
@Data
public class College{
 private Integer collegeId;
 private List<Student> student;
 private String collegeName;
}
------------------------------------------
@Data
public class University{
private Integer enrollmentNumber;
private List<College> college;
private String address;
 }
В приведенном выше коде мы видим, как Student, College, University связаны друг с другом. Давайте напишем код и посмотрим, как можно использовать наш метод fetchValue().

public String findStudent(University university){
  String studentName= university.getCollege().get(0).getStudent().get(0).getName();
// если какое-либо значение станет нулевым, это нарушит код и 
// возникнет NullPointerException. 
  String studentName= fetchValue(()->university.getCollege().get(0).getStudent().get(0).getName());
// в любое время, когда значение становится нулевым, имя студента будет нулевым, и исключение не будет выдано.
  }
Из приведенного выше кода мы видим, что во второй строке, где мы использовали метод fetchValue(), мы можем избежать исключения NullPointerException. Это очень полезно в сценариях, где есть цепь событий. Его можно использовать при проверке условий, например, при выяснении, присутствует значение или нет.

if(Objects.nonNull(fetchValue(()->university.getCollege().get(0).getStudent().get(0).getName()))){
// если значение присутствует, оно войдет в условие. В ином случае вернется null в Objects.nonNull, что сделает его false и оно не войдет в это условие.
}
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ