如何使用动态计时器执行技能效果?

epggiuax  于 2021-07-03  发布在  Java
关注(0)|答案(1)|浏览(286)

目前,我正在使用计时器来执行我的技能效果。所有技能效果每3秒做一次心跳。
这是我的密码:

public class EffectServiceImpl extends AbsServiceAdaptor<EffectConfig> {
    private static EffectServiceImpl instance;
    private FastList<Monster> existsEffectMonsterList;
    private Timer timer;
    public static EffectServiceImpl getInstance() {
        if(null == instance) {
            instance = new EffectServiceImpl();
        }
        return instance;
    }
    private EffectServiceImpl() {
        existsEffectMonsterList = new FastList<Monster>();
        timer = new Timer();
        timer.schedule(new MonsterEffectCheckTask(), 10000, 3000); // Heartbeat every 3 seconds
    }
    public class MonsterEffectCheckTask extends TimerTask {
        @Override
        public void run() {
            if(existsEffectMonsterList.size() > 0) {
                Monster monster;
                Effect effect;
                for(int i = 0; i < existsEffectMonsterList.size();) {
                    monster = existsEffectMonsterList.get(i);
                    if(monster.effectList.size() > 0) {
                        for(int j = 0; j < monster.effectList.size();) {
                            try {
                                effect = monster.effectList.get(j);
                                if(effect.heartbeat(monster)) {
                                    j++;
                                }
                            }
                            catch(Exception e) {
                                e.printStackTrace();
                                break;
                            }
                        }
                    }
                    if(monster.effectList.size() == 0) {
                        existsEffectMonsterList.remove(i);
                    }
                    else {
                        i++;
                    }
                }
            }
        }
    }
}

不过,我不希望所有的技能效果做心跳3秒。将有心跳技能小于3秒或大于3秒(即动态周期)。
所以我改了时间 timer.schedule 至1:

...
        timer.schedule(new MonsterEffectCheckTask(), 10000, 1);
    ...

然后添加 Thread.sleep 到timertask:

...
if(monster.effectList.size() > 0) {
    for(int j = 0; j < monster.effectList.size();) {
        try {
            effect = monster.effectList.get(j);
            if(effect.heartbeat(monster)) {
                j++;
            }
            Thread.sleep(effect.execTime); // This is dynamic time, each effect has an `execTime`. Code `public int execTime;`
        }
        catch(InterruptedException e) {
                e.printStackTrace();
        }
        catch(Exception e) {
            e.printStackTrace();
            break;
        }
    }
}
...

对于上面这样的代码,我应该:使用 schedule 或者 scheduleAtFixedRate 或者其他什么?有什么办法可以替换吗 Thread.sleep 万一你想“暂停”计时器?我应该设置什么 delay 以及 period (我知道如果我把它设为0,我会得到一个 IllegalArgumentException ,但如果设置为1则太短)?我想效果是心跳后,立即“暂停”的时间已经过了。此外,在同一心跳中可能有许多效果,但每个效果的“暂停”时间并不相同。
谢谢你的回答。

t1rydlwq

t1rydlwq1#

执行者框架 Timer 现在执行者框架已经过时了。请参见oracle的教程。

将您的任务定义为 Runnable 或者 Callable 物体。
使用由适当数量的线程支持的计划执行器服务。然后安排每个任务按您选择的时间间隔重复运行。
要检查或取消每个任务,请捕获 ScheduledFuture 对象返回给您。
如果要更改任务执行之间的时间间隔,请通过其 ScheduledFuture 对象。然后使用执行器服务重新安排新的时间间隔。
始终在应用程序结束前关闭executor服务。否则,后台线程池可能会像僵尸一样无限期地继续运行?。
并 Package 您的任务代码以捕获任何意外出现的异常。否则,未来的工作将悄无声息地停止。
所有这些都在堆栈溢出上被多次讨论过。所以我很简短。搜索以了解更多信息。下一次,在发布之前彻底搜索堆栈溢出。

示例代码

我制作了一个示例应用程序来展示如何使用executors框架更简单、更强大地管理后台线程工作。
我们定义一个 Monster 接口,有两个实现类, Demon & Witch . 我创建了这些类的一些对象。这些课程有一个 actOut 方法。我们的后台任务是运行这个方法。
对于每个现有的 Monster 例如,我们定义一个 Runnable 也就是说 Monster::actOut 方法。我们通过一个 ScheduledExecutorService 对象。执行器服务返回 ScheduledFuture 对象来跟踪我们计划的每个runnable。我们将这些未来的对象收集到 Demon 以及一份 Witch .
我们让它运行一分钟。过了这段时间,我们改变了音乐的节奏 Witch 任务。我们取消它们当前的任务,然后在两次执行之间安排一个新的可运行对象更长的时间间隔。我们让它再运行一分钟。之后,我们关闭应用程序。
(顺便说一句,我们可以回收现有的 Runnable 对象,而不是在重新调度时示例化新对象。做任何对你的需要有意义的事。)
这段代码使用了Java15中预览的一些即将推出的特性,比如密封类型和记录。但这些对这里的概念并不重要;您可以使用以前版本的java轻松地重新编写这段代码。

样品运行

运行示例:

---------|  Starting  |--------------------------------------------
This monster Demon named Crowley buys a soul at 2020-12-08T02:32:39Z
This monster Demon named Barthamus buys a soul at 2020-12-08T02:32:39Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:32:41Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:32:41Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:32:46Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:32:46Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:32:51Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:32:51Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:32:56Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:32:56Z
This monster Demon named Crowley buys a soul at 2020-12-08T02:32:59Z
This monster Demon named Barthamus buys a soul at 2020-12-08T02:32:59Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:33:01Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:33:01Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:33:06Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:33:06Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:33:11Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:33:11Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:33:16Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:33:16Z
This monster Demon named Crowley buys a soul at 2020-12-08T02:33:19Z
This monster Demon named Barthamus buys a soul at 2020-12-08T02:33:19Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:33:21Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:33:21Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:33:26Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:33:26Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:33:31Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:33:31Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:33:36Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:33:36Z
---------|  Changing speeds  |--------------------------------------------
This monster Witch named Rowena casts a spell at 2020-12-08T02:33:38Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:33:38Z
This monster Demon named Crowley buys a soul at 2020-12-08T02:33:39Z
This monster Demon named Barthamus buys a soul at 2020-12-08T02:33:39Z
This monster Demon named Crowley buys a soul at 2020-12-08T02:33:59Z
This monster Demon named Barthamus buys a soul at 2020-12-08T02:33:59Z
This monster Witch named Rowena casts a spell at 2020-12-08T02:34:18Z
This monster Witch named Tasha casts a spell at 2020-12-08T02:34:18Z
This monster Demon named Crowley buys a soul at 2020-12-08T02:34:19Z
This monster Demon named Barthamus buys a soul at 2020-12-08T02:34:19Z
---------|  Ending  |--------------------------------------------

源代码

我们有四节课: Monster.java (我们业务对象的接口) Demon.java (混凝土等级) Witch.java (混凝土等级) MonsterMash.java (应用程序类)
代码:

package work.basil.example;

public sealed interface Monster
        permits Demon, Witch
{
    String name ( ); // This getter method implemented implicitly by `record` in our concrete classes `Demon` & `Witch`.

    public void actOut ( );
}
package work.basil.example;

import java.time.Instant;
import java.time.temporal.ChronoUnit;

public record Demon(String name) implements Monster
{
    @Override
    public void actOut ( )
    {
        System.out.println( "This monster " + this.getClass().getSimpleName() + " named " + this.name + " buys a soul at " + Instant.now().truncatedTo( ChronoUnit.SECONDS ) );
    }
}
package work.basil.example;

import java.time.Instant;
import java.time.temporal.ChronoUnit;

public record Witch(String name) implements Monster
{
    @Override
    public void actOut ( )
    {
        System.out.println( "This monster " + this.getClass().getSimpleName() + " named " + this.name + " casts a spell at " + Instant.now().truncatedTo( ChronoUnit.SECONDS ) );
    }
}
package work.basil.example;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * Example for showing a change in cadence to scheduled tasks.
 */
public class MonsterMash
{
    public static void main ( String[] args )
    {
        System.out.println( "Hello World!" );
        MonsterMash app = new MonsterMash();
        app.demo();
    }

    private void demo ( )
    {
        // Instantiate Monster objects.
        List < Monster > monsters = List.of(
                new Demon( "Crowley" ) ,
                new Demon( "Barthamus" ) ,
                new Witch( "Rowena" ) ,
                new Witch( "Tasha" )
        );
        System.out.println( "monsters = " + monsters );

        // Schedule each monster to do some work periodically.
        System.out.println( "---------|  Starting  |--------------------------------------------" );
        ScheduledExecutorService ses = null;
        try
        {
            ses = Executors.newSingleThreadScheduledExecutor();

            final List < ScheduledFuture > demonFutures = new ArrayList <>();
            final List < ScheduledFuture > witchFutures = new ArrayList <>();
            for ( Monster monster : monsters )
            {
                Runnable runnable = monster :: actOut;  // Method reference used here for shorter syntax. 

                // Remember these futures.
                if ( monster instanceof Demon )
                {
                    ScheduledFuture scheduledFuture = ses.scheduleAtFixedRate( runnable , 1 , 20 , TimeUnit.SECONDS );
                    demonFutures.add( scheduledFuture );
                }
                if ( monster instanceof Witch )
                {
                    ScheduledFuture scheduledFuture = ses.scheduleAtFixedRate( runnable , 3 , 5 , TimeUnit.SECONDS );
                    witchFutures.add( scheduledFuture );
                }
            }

            // Wait a while to let the scheduled tasks do their work on background thread(s).
            // Then alter the cadence of the tasks’ execution.
            try
            {
                Thread.sleep( TimeUnit.MINUTES.toMillis( 1 ) );
                System.out.println( "---------|  Changing speeds  |--------------------------------------------" );
                for ( ScheduledFuture witchFuture : witchFutures )
                {
                    witchFuture.cancel( false );
                }
                witchFutures.clear();
                for ( Monster monster : monsters )
                {
                    if ( monster instanceof Witch )
                    {
                        Runnable runnable = monster :: actOut;
                        ScheduledFuture scheduledFuture = ses.scheduleAtFixedRate( runnable , 0 , 40 , TimeUnit.SECONDS );
                        witchFutures.add( scheduledFuture );
                    }
                }
                Thread.sleep( TimeUnit.MINUTES.toMillis( 1 ) );

                System.out.println( "---------|  Ending  |--------------------------------------------" );
            }
            catch ( InterruptedException e )
            {
                e.printStackTrace();
            }
        }
        finally
        {
            if ( Objects.nonNull( ses ) ) { ses.shutdown(); }
        }
    }
}

相关问题