Pull to refresh

Распараллеливание с минимальными правками в коде

Reading time1 min
Views13K
Пусть у вас есть метод, вызываемый во многих местах, и вызов которого хочется сделать параллельным. Это можно сделать, не меняя код вызова метода и код самого метода. Нужно только создать расширение объемлющего класса, и изменить код создания объекта.

Было:
class Service {
  public void longJob(Object arg) {...}
}
...
Service s=new Service();
...

s.longJob(arg);


Стало:
class Service {
  public void longJob(Object arg) {...}
}
class ServiceWrapper extends Service {
...
}
...
Service s=new ServiceWrapper() ;
...

s.longJob(arg);



Основная доработка состоит в переопределении распараллеливаемого метода:
class ServiceWrapper extends Service {
  SerialExecutor executor=new SerialExecutor(trueExecutor);

   public void longJob(final Object arg) {
       executor.execute(new Runnable() {
              public void run() {
                   ServiceWrapper.super.longJob(arg);
               }
        });
   }
}

SerialExecutor можно взять из документации на java.util.concurrent.Executor. Оптимизированный вариант — у меня в github.com/rfqu/CodeSamples. Он исполняет поданые ему задачи последовательно, тем самым избавляя от необходимости вводить синхронизацию в метод longJob(): все вызовы этого метода будут исполняться по очереди. Если в классе Service несколько публичных методов, их все надо переопределить тем же способом, и все они будут выполняться последовательно, из одной очереди.

Разумеется, этот способ применим не всегда и не решает всех проблем. Например, более крупные правки потребуются, если метод возвращает значение, или если один публичный метод вызывает другой публичный распаралелленый метод.

Идея с переопределением взята из Project Lombok.
Tags:
Hubs:
Total votes 37: ↑22 and ↓15+7
Comments37

Articles