Шаблон проектирования активных объектов разделяет выполнение метода и вызов метода для объектов, каждый из которых находится в своем собственном потоке управления. [1] Цель состоит в том, чтобы внедрить параллелизм , используя асинхронный вызов метода и планировщик для обработки запросов. [2]
Узор состоит из шести элементов: [3]
Пример шаблона активного объекта в Java . [4]
Во-первых, мы видим стандартный класс, который предоставляет два метода, которые устанавливают double в определенное значение. Этот класс НЕ соответствует шаблону активного объекта.
класс МойКласс { частный двойной val = 0.0 ; void doSomething () { val = 1.0 ; } void doSomethingElse () { val = 2.0 ; } }
Класс опасен в многопоточном сценарии, потому что оба метода могут быть вызваны одновременно, поэтому значение val (которое не является атомарным — оно обновляется в несколько шагов) может быть неопределенным — классическое состояние гонки. Конечно, вы можете использовать синхронизацию для решения этой проблемы, что в этом тривиальном случае легко. Но как только класс становится реалистично сложным, синхронизация может стать очень сложной. [5]
Чтобы переписать этот класс как активный объект, можно сделать следующее:
класс МойАктивныйОбъект { private double val = 0.0 ; private BlockingQueue < Runnable > dispatchQueue = new LinkedBlockingQueue < Runnable > (); public MyActiveObject () { new Thread ( new Runnable () { @Override public void run () { try { while ( true ) { dispatchQueue . take (). run (); } } catch ( InterruptedException e ) { // хорошо, просто завершаем работу диспетчера } } } ). start (); } void doSomething () выдает InterruptedException { dispatchQueue.put ( new Runnable ( ) { @Override public void run () { val = 1.0 ; } } ) ; } void doSomethingElse () выдает InterruptedException { dispatchQueue.put ( new Runnable () { @Override public void run ( ) { val = 2.0 ; } } ) ; } }
Другой пример шаблона активного объекта в Java, реализованный в Java 8, предоставляющий более короткое решение.
public class MyClass { private double val ; // контейнер для задач // решает, какой запрос выполнить следующим // asyncMode=true означает, что наш рабочий поток обрабатывает свою локальную очередь задач в порядке FIFO // только один поток может изменять внутреннее состояние private final ForkJoinPool fj = new ForkJoinPool ( 1 , ForkJoinPool . defaultForkJoinWorkerThreadFactory , null , true ); // реализация метода активного объекта public void doSomething () throws InterruptedException { fj . execute (() -> { val = 1.0 ; }); } // реализация метода активного объекта public void doSomethingElse () throws InterruptedException { fj . execute (() -> { val = 2.0 ; }); } }