Gymterview
senior

Что такое модель акторов и как она реализована в Java?

Модель акторов (Actor Model) — это математическая модель параллельных вычислений (Карл Хьюитт, 1973), в которой актор является базовой единицей вычислений. Каждый актор:

  1. Получает сообщения и обрабатывает их по одному
  2. Может создавать новых акторов
  3. Может отправлять сообщения другим акторам
  4. Может изменять своё внутреннее состояние

Ключевая идея: акторы никогда не разделяют состояние. Вся коммуникация — через асинхронную передачу сообщений. Это исключает проблемы синхронизации, deadlock и race condition по своей природе.

Основные принципы:

  • Каждый актор имеет «почтовый ящик» (mailbox) — очередь входящих сообщений.
  • Сообщения обрабатываются последовательно — внутри актора не нужна синхронизация.
  • Отправка сообщений асинхронна и неблокирующая.
  • Акторы идентифицируются по адресу (ActorRef), а не по ссылке на объект.

Реализации в Java:

1. Akka/Pekko — наиболее известная реализация

Код: актор на Akka
public class GreeterActor extends AbstractActor {
    private int greetingCount = 0; // Состояние — безопасно без синхронизации

    @Override
    public Receive createReceive() {
        return receiveBuilder()
            .match(String.class, name -> {
                greetingCount++;
                getSender().tell("Привет получен!", getSelf());
            })
            .match(GetCount.class, msg -> {
                getSender().tell(greetingCount, getSelf());
            })
            .build();
    }

    public static Props props() {
        return Props.create(GreeterActor.class);
    }
}

// Использование
ActorSystem system = ActorSystem.create("mySystem");
ActorRef greeter = system.actorOf(GreeterActor.props(), "greeter");
greeter.tell("Мир", ActorRef.noSender()); // fire-and-forget

Примечание: Akka изменил лицензию на BSL в 2022 году. Форк Apache Pekko продолжает развитие под Apache 2.0.

2. Упрощённая реализация на Virtual Threads:

Код: простой актор на BlockingQueue + Virtual Thread
public abstract class SimpleActor {
    private final BlockingQueue<Object> mailbox = new LinkedBlockingQueue<>();
    private final Thread thread;

    protected SimpleActor() {
        this.thread = Thread.ofVirtual().start(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Object message = mailbox.take();
                    onReceive(message);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
    }

    protected abstract void onReceive(Object message);

    public void send(Object message) {
        mailbox.offer(message);
    }

    public void stop() {
        thread.interrupt();
    }
}

// Конкретный актор
class CounterActor extends SimpleActor {
    private int count = 0;

    @Override
    protected void onReceive(Object message) {
        if (message instanceof String cmd) {
            switch (cmd) {
                case "increment" -> count++;
                case "get" -> System.out.println("Count: " + count);
            }
        }
    }
}

Сравнение с традиционной многопоточностью:

Характеристика Shared State Actor Model
Состояние Общее, защищённое блокировками Изолированное внутри актора
Коммуникация Через общую память Через сообщения
Синхронизация Явная (synchronized, Lock) Не нужна
Deadlock Возможен Невозможен (нет блокировок)
Масштабирование Сложно Естественно

Обработка ошибок — принцип «let it crash»: если актор упал, его супервизор (supervisor) решает: перезапустить актор, эскалировать ошибку или остановить его.

Частые ошибки:

  • Передача изменяемых объектов как сообщений — нарушает изоляцию. Сообщения должны быть иммутабельными.
  • Блокирующие вызовы внутри актора (future.get()) — блокирует обработку всех сообщений.
  • Patterns.ask повсеместно вместо tell — снижает производительность.

Актуальность: Apache Pekko — основная реализация. Модель акторов используется в IoT, игровых серверах, финансовых системах. С Virtual Threads простые сценарии можно реализовать без тяжёлых фреймворков.

Аналогия: модель акторов — это организация работы через записки. Каждый сотрудник (актор) сидит в своём кабинете (изолированное состояние), получает записки (сообщения) во входящий лоток (mailbox) и обрабатывает их по одной. Никто не заходит к нему в кабинет и не трогает его документы — общение только через записки.

На собеседовании покажите понимание trade-offs: модель акторов устраняет проблемы разделяемого состояния, но усложняет отладку (асинхронные сообщения), тестирование и добавляет накладные расходы на сериализацию. Для Java-проектов без кластерного распределения Virtual Threads + Structured Concurrency часто являются более простой альтернативой.