Я реализовал собственный планировщик задач / заданий поверх существующих Java SchedulerExecutorService и ExecutorService.
Так что теперь у меня есть следующий вопрос. Может ли это быть полезным, если я уменьшу свои синхронизированные блоки, но получу - если я делаю это - иногда один, еще два спина?
В конце у меня есть еще несколько вопросов о синхронизированных и изменчивых в однопоточномсистема. Так что я рекомендую читать дальше, это будет захватывающе - и сложно ^^
Так что я отправляю некоторый код от себя. Это всего лишь несколько фрагментов кода из большой сети классов.
поля:
public final AtomicBoolean canceld = new AtomicBoolean();
protected Future<?> currentFuture = null;
методы из разных, но связанных классов (через наследование, ссылки):
@Override
public void run()
{
try
{
synchronized (canceld)
{
currentFuture = this.s.executor.submit(() ->
{
try
{
super.run();
}
finally
{
synchronized (canceld)
{
if (canceld.get()) return;
currentFuture = this.s.stpe.schedule(this, delay, timeunit);
}
}
});
}
}
catch (Throwable e)
{
e.printStackTrace();
}
}
stpe является ссылкой на существующий ScheduledExecutorService. Исполнитель - это ссылка на «обычного» Исполнителя.
super.run()
выглядит так:
runJob
содержит мою бизнес-логику этой работы (лямбда-выражение в видевызывающего моего планировщика)
@Override
public void run()
{
if (!jobReadyPhaser.up()) return;
try
{
runJob.handle(this);
}
catch (Throwable e)
{
e.printStackTrace();
}
finally
{
jobReadyPhaser.down();
}
}
И в одном случае мой jobReadyPhaser
выглядит следующим образом. У меня там другая работа ReadyPhaser;если планировщик-клиент знает, что ему не нужна эта информация, если задача все еще выполняется или нет, то в ложном случае позади jobReadyPhaser не используется фазер;лучше для производительности - я думаю. (здесь вы можете увидеть, как создается экземпляр jobReadyPhaser: Вызов в конструкторе метода с параметром this объекта / конструктора
public boolean up()
{
//synchronized (job.canceld)
//{
if (job.canceld.get()) return false;
ph.register();
//}
return true;
}
Вот несколько строкпрокомментировал, потому что я думаю, что мне не нужно синхронизироваться здесь, ни в коем случае. Это верно?
@Override
public void cancel(ScheduledFuture<?> fut, boolean _mayInterruptIfRunning)
{
this.canceld.set(true);
synchronized (this.canceld)
{
fut.cancel(_mayInterruptIfRunning);
if (this.currentFuture != null) this.currentFuture.cancel(_mayInterruptIfRunning);
}
this.s.jobs.remove(this);
}
Фут как параметр не нужно здесь знать, может быть, я могу переместить его из этого синхронизированного блока. Это первоначальный запланированныйExecutorService - будущее из него. Иногда это планировщик, который срабатывает с фиксированной скоростью или с фиксированной задержкой, поэтому я отменяю их и здесь. Часто это таймер с одним выстрелом, а другие кадры были сделаны из моей собственной реализациикоторый вы можете увидеть в моем примере, который я разместил здесь.
Так что, если я выполню свой метод отмены, то я надеюсь, что мой код сделает следующее:
это отменит начальное будущее.
отменяет «текущее будущее»
не позволяет больше выполнять мою бизнес-логику, если она сейчас не находится в режиме исполнения
если _mayInterruptIfRunning == true
то текущее выполнение моей логики бизнеса получает прерывание.
Счетчик фазера вверх и вниз (если я включил свой фазер), и после отмены этого задания я могу использовать фазер блокирующим образом, чтобы дождаться завершения всего текущего выполнения моей логики бизнеса.
Так что, если я сейчас удалю эти синхронизированные блоки, что я получу?
[да] это отменит начальное будущее.
[это зависит от планирования потока]отмените «текущее будущее»
[я надеюсь да], оно не позволяет больше выполнять мою бизнес-логику, если она сейчас не находится в режиме выполнения
[я надеюсь да] если _mayInterruptIfRunning == true
тогда текущее выполнение моей бизнес-логики получит прерывание.
[я надеюсь да] Счетчик фазера вверх и вниз (если я включил свой фазер), и после отмены этой работы я могу использоватьФазер в блокирующем режиме, чтобы ждать, что все текущее выполнение моей логики бизнеса сделано.
Таким образом, логика остается неизменной. Но, возможно, другая задача передается ScheduledExecutor или Executor. Но логика бизнеса будет выполнена, если выполненная задача будет выполнена, потому что атомарное отмене останавливает выполнение.
в моем предыдущем решении у меня нет необходимости повторно передавать шаблон кода существующим планировщикам / исполнителям, но у меня есть много синхронизированных вещей.
если я его рефакторинг, удалитесинхронизируемый материал, тогда я получаю еще одно вращение.
Так что мой вопрос - еще одно вращение VS синхронизировано.
насколько дорогая моя синхронизация?
код с синхронизированным большую часть времени выполняется только одним потоком. Только если я отменю работу, тогда будут активны две темы. (Хорошо, и только тогда: у меня было бы одно бесполезное больше вращения, если я удалю синхронизированный).
Если я удалю это синхронизированное, у меня все еще есть моя переменная переменная, atomicBoolean.
Так что в большинстве случаев есть только один поток.
Есть ли разница между синхронизированным и изменчивым, если есть только один поток?
Если я использую 10энергозависимые переменные VS 1 синхронизированный блок? Что быстрее (один поток!)
Хорошо, в моем коде я использую синхронизированные вещи в разных позициях, также в моем методе выполнения. Итак, у меня есть много входов и мониторов.
Один большой синхронизированный лучше, чем несколько маленьких? (в одном потоке!) много мониторов входит и существует против одного входа и выхода из монитора?
И для моего примера вопрос: вы бы предпочли, чтобы повторно отправить задачу в schedulerService / Executorservice, которая впоследствии будет отменена? в методе выполнения с этим атомным логическим значением? Или вы бы предпочли решение, как я написал, которое не позволяет ro повторно отправлять пустые задачи после отмены, но с несколькими синхронизированными блоками?
Так что после того, как я написал этот текст здесь, я не уверен, что мой код фазеравсе верно.
private final Phaser ph = new Phaser(1);
public boolean up()
{
if (job.canceld.get()) return false; //A
//B
ph.register(); //C
//D
return true;
}
1) Поток X выполнит up () до // B
2) Поток Z выполнит метод отмены -> cancelld == true
3) Поток Z теперь выполняет метод, чтобы проверить, выполняется ли еще задание: ph.awaitAdvanceInterruptibly(ph.arrive());
Поскольку ph.register
в // C сейчас не выполняется, ph.await.....
не заблокируется и скажет: тамразве нет какой-либо логики выполнения
4) Поток X выполняет ph.register()
, но поток Z не получает эту информацию, потому что он уже проверил фазер.
Хорошо, каково было бы решение здесь? Я думаю, что я должен "сгруппировать" проверку canceld
и ph.register()
и синхронизировать это. Но я также синхронизировал в cancel()
-методе canceld.set(true)
.
Но это не зависит от остальных, поэтому мой вопрос верен: лучше ли будет удалить синхронизированные блоки, которые вы видели в моем примереИ я думаю, что в конце я прав: я должен синхронизировать Phaser
с canceld
Приятные приветствия
Редактировать:
Если я реорганизую его, удалим синхронизированный материал вокруг этого currentFuture, то я должен сделать это currentFuture изменчивым, чтобы поток метода отмены мог видеть currentFuture.
Так что в этом случае я удаляю синхронизированные, но у меня там много изменчивых записей. Так будет ли большой разницей, если у меня там будет синхронизация или изменчивость в контексте, то есть большую часть времени выполняется одним потоком?
Если я скажу, я бы тоже удалил эти изменчивые вещи, тогда я могуудалить это текущее будущее, а также. В этом случае у меня в каждом случае (и не только в гоночных) больше вращения.
Итак, у меня есть три решения:
мое синхронизированное решение: без дополнительного вращения.
решение без sycnhronized, но энергозависимое от currentFuture: в редких случаях у меня возникают дополнительные спины без бизнес-кода.
решение без синхронизации и без энергозависимости currentFuture: если память не является когерентной, то это будетСкорее всего при каждой отмене, что у меня есть дополнительное вращение без бизнес-кода.
Хорошо, момент в моем третьем решении, не было бы future.cancel(true)
, myInterupt-вещь возможна;Хорошо, так что я думаю, что это действительно не решение для меня.
Если я все это придумаю, то я думаю, что myInterupt-вещь этой будущей отмены всегда достигнет кода, если выполняется текущий бизнес-код(во второстепенном решении, энергозависимом и несинхронизированном решении)
Так что мне делать?