← Назад ко всем вопросам

Какие знаешь классы для многопоточности в Java

1️⃣ Как кратко ответить

В Java для многопоточности используются классы Thread, Runnable, Callable, Future, ExecutorService, ScheduledExecutorService, ForkJoinPool, CompletableFuture, а также классы из пакета java.util.concurrent, такие как CountDownLatch, CyclicBarrier, Semaphore, ReentrantLock, ReadWriteLock, BlockingQueue и другие.

2️⃣ Подробное объяснение темы

Многопоточность в Java позволяет выполнять несколько потоков одновременно, что может значительно улучшить производительность приложений. Для этого Java предоставляет множество классов и интерфейсов, которые помогают управлять потоками и синхронизировать их работу.

Основные классы и интерфейсы для работы с потоками

  1. Thread

    • Класс Thread представляет собой поток выполнения в программе. Вы можете создать новый поток, расширив этот класс и переопределив его метод run().
    • Пример:
      class MyThread extends Thread {
          public void run() {
              System.out.println("Thread is running");
          }
      }
      ​
      public class Main {
          public static void main(String[] args) {
              MyThread thread = new MyThread();
              thread.start(); // Запускает новый поток, который выполняет метод run()
          }
      }
      
  2. Runnable

    • Интерфейс Runnable используется для определения задачи, которая может быть выполнена в потоке. Он содержит единственный метод run().
    • Пример:
      class MyRunnable implements Runnable {
          public void run() {
              System.out.println("Runnable is running");
          }
      }
      ​
      public class Main {
          public static void main(String[] args) {
              Thread thread = new Thread(new MyRunnable());
              thread.start(); // Запускает новый поток, который выполняет метод run() из MyRunnable
          }
      }
      
  3. Callable и Future

    • Callable — это интерфейс, похожий на Runnable, но он может возвращать результат и выбрасывать исключение.
    • Future используется для получения результата выполнения Callable.
    • Пример:
      import java.util.concurrent.Callable;
      import java.util.concurrent.ExecutionException;
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      import java.util.concurrent.Future;
      ​
      class MyCallable implements Callable<String> {
          public String call() {
              return "Callable result";
          }
      }
      ​
      public class Main {
          public static void main(String[] args) {
              ExecutorService executor = Executors.newSingleThreadExecutor();
              Future<String> future = executor.submit(new MyCallable());
      ​
              try {
                  String result = future.get(); // Получает результат выполнения Callable
                  System.out.println(result);
              } catch (InterruptedException | ExecutionException e) {
                  e.printStackTrace();
              } finally {
                  executor.shutdown(); // Завершает работу ExecutorService
              }
          }
      }
      
  4. ExecutorService и ScheduledExecutorService

    • ExecutorService — это интерфейс, который предоставляет методы для управления потоками, включая их запуск и завершение.
    • ScheduledExecutorService расширяет ExecutorService и добавляет возможность планирования задач.
    • Пример:
      import java.util.concurrent.Executors;
      import java.util.concurrent.ScheduledExecutorService;
      import java.util.concurrent.TimeUnit;
      ​
      public class Main {
          public static void main(String[] args) {
              ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
      ​
              Runnable task = () -> System.out.println("Scheduled task executed");
      ​
              scheduler.schedule(task, 5, TimeUnit.SECONDS); // Планирует выполнение задачи через 5 секунд
      ​
              scheduler.shutdown(); // Завершает работу ScheduledExecutorService
          }
      }
      
  5. ForkJoinPool

    • ForkJoinPool — это специальный вид пула потоков, который используется для выполнения задач, которые могут быть разбиты на более мелкие подзадачи.
    • Пример:
      import java.util.concurrent.RecursiveTask;
      import java.util.concurrent.ForkJoinPool;
      ​
      class Fibonacci extends RecursiveTask<Integer> {
          final int n;
      ​
          Fibonacci(int n) { this.n = n; }
      ​
          protected Integer compute() {
              if (n <= 1) return n;
              Fibonacci f1 = new Fibonacci(n - 1);
              Fibonacci f2 = new Fibonacci(n - 2);
              f1.fork(); // Асинхронно запускает подзадачу
              return f2.compute() + f1.join(); // Ждет завершения f1 и возвращает результат
          }
      }
      ​
      public class Main {
          public static void main(String[] args) {
              ForkJoinPool pool = new ForkJoinPool();
              int result = pool.invoke(new Fibonacci(10)); // Запускает задачу Fibonacci
              System.out.println("Fibonacci result: " + result);
          }
      }
      
  6. CompletableFuture

    • CompletableFuture — это класс, который позволяет работать с асинхронными вычислениями и комбинировать их.
    • Пример:
      import java.util.concurrent.CompletableFuture;
      ​
      public class Main {
          public static void main(String[] args) {
              CompletableFuture.supplyAsync(() -> "Hello")
                  .thenApply(result -> result + " World")
                  .thenAccept(System.out::println); // Выводит "Hello World"
          }
      }
      

Синхронизация и управление потоками

  1. CountDownLatch

    • CountDownLatch позволяет одному или нескольким потокам ждать, пока не завершатся операции в других потоках.
    • Пример:
      import java.util.concurrent.CountDownLatch;
      ​
      public class Main {
          public static void main(String[] args) throws InterruptedException {
              CountDownLatch latch = new CountDownLatch(3);
      ​
              Runnable task = () -> {
                  System.out.println("Task completed");
                  latch.countDown(); // Уменьшает счетчик на 1
              };
      ​
              new Thread(task).start();
              new Thread(task).start();
              new Thread(task).start();
      ​
              latch.await(); // Ждет, пока счетчик не станет равным 0
              System.out.println("All tasks completed");
          }
      }
      
  2. CyclicBarrier

    • CyclicBarrier позволяет группе потоков ждать друг друга, пока все не достигнут определенной точки выполнения.
    • Пример:
      import java.util.concurrent.BrokenBarrierException;
      import java.util.concurrent.CyclicBarrier;
      ​
      public class Main {
          public static void main(String[] args) {
              CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("Barrier reached"));
      ​
              Runnable task = () -> {
                  try {
                      System.out.println("Task before barrier");
                      barrier.await(); // Ждет, пока все потоки не вызовут await()
                      System.out.println("Task after barrier");
                  } catch (InterruptedException | BrokenBarrierException e) {
                      e.printStackTrace();
                  }
              };
      ​
              new Thread(task).start();
              new Thread(task).start();
              new Thread(task).start();
          }
      }
      
  3. Semaphore

    • Semaphore управляет доступом к ресурсу с помощью счетчика разрешений.
    • Пример:
      import java.util.concurrent.Semaphore;
      ​
      public class Main {
          public static void main(String[] args) {
              Semaphore semaphore = new Semaphore(2); // Разрешает доступ двум потокам одновременно
      ​
              Runnable task = () -> {
                  try {
                      semaphore.acquire(); // Получает разрешение
                      System.out.println("Accessing resource");
                      Thread.sleep(1000); // Симулирует работу с ресурсом
                      semaphore.release(); // Освобождает разрешение
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              };
      ​
              new Thread(task).start();
              new Thread(task).start();
              new Thread(task).start();
          }
      }
      
  4. ReentrantLock и ReadWriteLock

    • ReentrantLock — это замок, который позволяет потокам захватывать его несколько раз.
    • ReadWriteLock предоставляет отдельные замки для операций чтения и записи.
    • Пример использования ReentrantLock:
      import java.util.concurrent.locks.ReentrantLock;
      ​
      public class Main {
          public static void main(String[] args) {
              ReentrantLock lock = new ReentrantLock();
      ​
              Runnable task = () -> {
                  lock.lock(); // Захватывает замок
                  try {
                      System.out.println("Locked section");
                  } finally {
                      lock.unlock(); // Освобождает замок
                  }
              };
      ​
              new Thread(task).start();
              new Thread(task).start();
          }
      }
      
  5. BlockingQueue

    • BlockingQueue — это очередь, которая поддерживает операции, ожидающие, пока очередь не станет непустой при извлечении, и операции, ожидающие, пока в очередь не будет добавлен элемент.
    • Пример:
      import java.util.concurrent.ArrayBlockingQueue;
      import java.util.concurrent.BlockingQueue;
      ​
      public class Main {
          public static void main(String[] args) {
              BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
      ​
              Runnable producer = () -> {
                  try {
                      queue.put("Element"); // Добавляет элемент в очередь
                      System.out.println("Element added");
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              };
      ​
              Runnable consumer = () -> {
                  try {
                      String element = queue.take(); // Извлекает элемент из очереди
                      System.out.println("Element taken: " + element);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              };
      ​
              new Thread(producer).start();
              new Thread(consumer).start();
          }
      }
      

Эти классы и интерфейсы предоставляют мощные инструменты для создания многопоточных приложений в Java, позволяя эффективно управлять потоками и синхронизировать их работу.

Тема: Многопоточность
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки