线程


1 概念辨析

1.1 并行(Parallel)

同时执行多个任务。

--------------------------> 任务1
--------------------------> 任务2
--------------------------> 任务3

1.2 串行(Serial)

依次执行多个任务。

  任务1    任务2    任务3
-------->-------->-------->

1.3 并发(Concurrence)

在多个任务之间轮流切换,宏观看是并行的,微观则是串行的。

----        ----        --> 任务1
    ----        ----      > 任务2
        ----        ----  > 任务3

1.4 同步(Synchronization)

一个任务必须等待另一个任务执行完以后再继续执行。

-----                -----> 任务1
     -----     ----->       任务2
          ---->             任务3

1.5 异步(Asynchronization)

一个任务无须等待另一个任务执行完即可以继续执行。

--------------------------> 任务1
     --------------->       任务2
          ---->             任务3

2 线程管理

在启动应用时,系统会为该应用创建一个被称为主线程的执行过程。该执行过程随应用的启动而创建,随应用的终止而销毁,是应用的核心线程。用户界面的显示和更新等操作都是在主线程中完成的,因此主线程亦称UI线程。默认情况下,应用的所有操作都是在主线程中执行的。

如果需要执行比较耗时的任务,如下载文件、访问数据库等,为了不使用户界面因主线程被阻塞和出现卡顿,影响用户体验,甚至迟滞其它任务的执行,可以将这些耗时任务放在独立于主线程之外的辅助线程中执行。

Java语言本身提供了完善的多线程机制,是实现并发的重要技术手段,包含基本的Thread类和Runnable接口。但随着应用的业务逻辑变得越来越复杂,很多时候往往需要创建多个辅助线程,并发执行多个任务。线程之间可能还需要交换数据和同步进度。程序代码会因此变得异常复杂且难以维护。为了简化多线程应用的开发,鸿蒙系统提供了两种机制,帮助解决线程管理问题:

3 任务分发

3.1 任务分发器(TaskDispatcher)

在鸿蒙中,除了使用Java的Thread类和Runnable接口实现多线程以外,还可以借助任务分发器(TaskDispatcher)实现在不同线程中的任务分发。TaskDispatcher是一个Java接口(Interface),也是Ability分发任务的基本接口。

鸿蒙中的线程并不是平等的,而是被分为三个优先级,定义在TaskPriority枚举中:

在主线程上执行的任务默认拥有最高优先级。如果某个任务并不急于获得结果,采用较低的优先级更为合理。

作为接口的TaskDispatcher拥有多个实现,每个实现对应不同的任务分发策略。在分发任务时可以指定任务的优先级,由同一个任务分发器分发的任务优先级相同。

TaskDispatcher
|
|___GlobalTaskDispatcher   - 全局任务分发器
|___ParallelTaskDispatcher - 并行任务分发器
|___SerialTaskDispatcher   - 串行任务分发器
|___SpecTaskDispatcher     - 专有任务分发器

3.1.1 全局任务分发器(GlobalTaskDispatcher)

3.1.2 并行任务分发器(ParallelTaskDispatcher)

3.1.3 串行任务分发器(SerialTaskDispatcher)

3.1.4 专有任务分发器(SpecTaskDispatcher)

专有任务分发器是绑定到专有线程上的任务分发器。目前已有的专有线程是主线程,即UI线程。

SpecTaskDispatcher
|
|___MainTaskDispatcher - 主线程专有任务分发器 \
|                                            > 它们其实是一样的
|___UITaskDispatcher   - UI线程专有任务分发器 /  <-建议使用这个
3.1.4.1 主线程专有任务分发器(MainTaskDispatcher)

默认情况下主线程不能执行过多任务,通过这个分发器就可以将任务绑定到主线程上,使之执行更多的任务。

3.1.4.2 UI线程专有任务分发器(UITaskDispatcher)

默认情况下UI线程不能执行过多任务,通过这个分发器就可以将任务绑定到UI线程上,使之执行更多的任务。

taskDispatcher.asyncDispatch(new Runnable() {
    @Override
    public void run() {
        // 更新界面
    }
});

3.2 任务分发器的方法

在获得或创建以上各种任务分发器对象之后,即可通过调用其中的方法,在线程中分发任务。

3.2.1 同步分发(syncDispatch)

分发任务并在当前线程等待任务完成。表示任务的run()方法返回前,当前线程会阻塞。

taskDispatcher.syncDispatch(new Runnable() {
    @Override
    public void run() {
        // 执行任务
    }
});

同步分发使用不当极易导致线程死锁:

3.2.2 异步分发(asyncDispatch)

分发任务并立即返回一个用于取消该任务的接口(Revocable)。

Revocable revocable = taskDispatcher.asyncDispatch(new Runnable() {
    @Override
    public void run() {
        // 执行任务
    }
});

所返回的Revocable对象可被用于取消任务。

3.2.3 异步延迟分发(delayDispatch)

分发任务并立即返回一个用于取消该任务的接口(Revocable)。系统内部会在指定时间后将任务排入等候队列。所指定的延迟时间仅表示任务入队的时间,任务实际被执行的时间可能晚于这个时间,具体晚多久取决于等候队列的长度及内部线程池的繁忙程度。

Revocable revocable = taskDispatcher.delayDispatch(new Runnable() {
    @Override
    public void run() {
        // 执行任务
    }
}, 5000);
    ^
    |__延迟时间毫秒值

所返回的Revocable对象可被用于取消任务。

3.2.4 异步组分发(asyncGroupDispatch)

任务组由彼此存在某种联系的多个任务组成。可以指定在组内任务都执行完以后执行的终结任务。

Group group = taskDispatcher.createDispatchGroup();

Revocable revocable1 = taskDispatcher.asyncGroupDispatch(group, new Runnable() {
    @Override
    public void run() {
        // 一号任务
    }
});

Revocable revocable2 = taskDispatcher.asyncGroupDispatch(group, new Runnable() {
    @Override
    public void run() {
        // 二号任务
    }
});

taskDispatcher.groupDispatchNotify(group, new Runnable() {
    @Override
    public void run() {
        // 终结任务
    }
});

所返回的Revocable对象可被用于取消任务。

3.2.5 取消任务(revoke)

只有asyncDispatch()、delayDispatch()和asyncGroupDispatch()三个方法,返回Revocable对象,也只有通过这三个方法分发的异步任务,才能被取消。

boolean revoked = revocable.revoke();

只能取消尚未开始执行的任务,无法取消正在执行或已经完成的任务,对于后者revoke()返回false。

3.2.6 分发屏障

3.2.6.1 同步分发屏障(syncDispatchBarrier)

在任务组上设置屏障,在任务组中的所有任务完成后执行屏障任务,并在完成后返回。

Group group = taskDispatcher.createDispatchGroup();

Revocable revocable1 = taskDispatcher.asyncGroupDispatch(group, new Runnable() {
    @Override
    public void run() {
        // 一号任务
    }
});

Revocable revocable2 = taskDispatcher.asyncGroupDispatch(group, new Runnable() {
    @Override
    public void run() {
        // 二号任务
    }
});

taskDispatcher.syncDispatchBarrier(new Runnable() {
    @Override
    public void run() {
        // 屏障任务
    }
});

不能通过全局任务分发器(GlobalTaskDispatcher)同步分发屏障任务。

3.2.6.2 异步分发屏障(asyncDispatchBarrier)

在任务组上设置屏障并立即返回,在任务组中的所有任务完成后执行屏障任务。

Group group = taskDispatcher.createDispatchGroup();

Revocable revocable1 = taskDispatcher.asyncGroupDispatch(group, new Runnable() {
    @Override
    public void run() {
        // 一号任务
    }
});

Revocable revocable2 = taskDispatcher.asyncGroupDispatch(group, new Runnable() {
    @Override
    public void run() {
        // 二号任务
    }
});

taskDispatcher.asyncDispatchBarrier(new Runnable() {
    @Override
    public void run() {
        // 屏障任务
    }
});

不能通过全局任务分发器(GlobalTaskDispatcher)异步分发屏障任务。

3.2.6.3 组分发屏障(groupDispatchBarrier)

在异步组分发的基础上设置更多的等候节点,即屏障任务。

Group group = taskDispatcher.createDispatchGroup();

Revocable revocable1 = taskDispatcher.asyncGroupDispatch(group, new Runnable() {
    @Override
    public void run() {
        // 一号任务
    }
});

Revocable revocable2 = taskDispatcher.asyncGroupDispatch(group, new Runnable() {
    @Override
    public void run() {
        // 二号任务
    }
});

taskDispatcher.groupDispatchBarrier(group, new Runnable() {
    @Override
    public void run() {
        // 屏障任务
    }

Revocable revocable3 = taskDispatcher.asyncGroupDispatch(group, new Runnable() {
    @Override
    public void run() {
        // 三号任务
    }
});

Revocable revocable4 = taskDispatcher.asyncGroupDispatch(group, new Runnable() {
    @Override
    public void run() {
        // 四号任务
    }
});

taskDispatcher.groupDispatchNotify(group, new Runnable() {
    @Override
    public void run() {
        // 终结任务
    }

此方法仅限于在并行任务分发器(ParallelTaskDispatcher)上使用。

终结任务也可以理解为一种屏障任务,故也可以通过groupDispatchBarrier()方法分发。

3.2.7 异步多次分发(applyDispatch)

以异步方式多次执行同一个任务。

taskDispatcher.applyDispatch(new Consumer<Long>() {
    @Override
    public void accept(Long index) {
        // 执行任务           ^
    }                        |__第几次执行
}, 3);
   ^
   |__执行次数

例程:Task

...\Task\entry\src\main\resources\base\graphic\background_button.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:shape="rectangle">
    <corners ohos:radius="100"/>
    <solid ohos:color="#00a2e8"/>
</shape>

...\Task\entry\src\main\resources\base\layout\ability_main.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:left_padding="60vp"
    ohos:right_padding="60vp"
    ohos:alignment="center"
    ohos:orientation="vertical"
    ohos:background_element="#000000">

    <Button
        ohos:id="$+id:btnSyncDispatch"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="同步分发"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

    <Button
        ohos:id="$+id:btnAsyncDispatch"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="异步分发"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

    <Button
        ohos:id="$+id:btnDelayDispatch"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="异步延迟分发"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

    <Button
        ohos:id="$+id:btnAsyncGroupDispatch"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="异步组分发"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

    <Button
        ohos:id="$+id:btnRevoke"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="取消任务"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

    <Button
        ohos:id="$+id:btnSyncDispatchBarrier"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="同步分发屏障"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

    <Button
        ohos:id="$+id:btnAsyncDispatchBarrier"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="异步分发屏障"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

    <Button
        ohos:id="$+id:btnApplyDispatch"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="异步多次分发"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

</DirectionalLayout>

...\Task\entry\src\main\java\com\minwei\task\slice\MainAbilitySlice.java

public class MainAbilitySlice extends AbilitySlice {
    private static final HiLogLabel label = new HiLogLabel(
        HiLog.LOG_APP, 0x00101, "Task");
    private final Calendar calendar = Calendar.getInstance();
    private final SimpleDateFormat simpleDateFormat =
        new SimpleDateFormat("HH:mm:ss.SSS");

    @Override
    public void onStart(Intent intent) {
        ...
        findComponentById(ResourceTable.Id_btnSyncDispatch)
            .setClickedListener(component -> syncDispatch());
        findComponentById(ResourceTable.Id_btnAsyncDispatch)
            .setClickedListener(component -> asyncDispatch());
        findComponentById(ResourceTable.Id_btnDelayDispatch)
            .setClickedListener(component -> delayDispatch());
        findComponentById(ResourceTable.Id_btnAsyncGroupDispatch)
            .setClickedListener(component -> asyncGroupDispatch());
        findComponentById(ResourceTable.Id_btnRevoke)
            .setClickedListener(component -> revoke());
        findComponentById(ResourceTable.Id_btnSyncDispatchBarrier)
            .setClickedListener(component -> syncDispatchBarrier());
        findComponentById(ResourceTable.Id_btnAsyncDispatchBarrier)
            .setClickedListener(component -> asyncDispatchBarrier());
        findComponentById(ResourceTable.Id_btnApplyDispatch)
            .setClickedListener(component -> applyDispatch());
    }
    ...
    private void timeConsuming() {
        for (int i = 0; i < 100000000; ++i);
    }

    private void syncDispatch() {
        TaskDispatcher taskDispatcher = getGlobalTaskDispatcher(
            TaskPriority.DEFAULT);

        HiLog.info(label, "任务1即将分发");
        taskDispatcher.syncDispatch(new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务1开始执行");
                timeConsuming();
                HiLog.info(label, "任务1执行完成");
            }
        });
        HiLog.info(label, "任务1分发完成");

        HiLog.info(label, "任务2即将分发");
        taskDispatcher.syncDispatch(new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务2开始执行");
                timeConsuming();
                HiLog.info(label, "任务2执行完成");
            }
        });
        HiLog.info(label, "任务2分发完成");

        HiLog.info(label, "任务3即将分发");
        taskDispatcher.syncDispatch(new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务3开始执行");
                timeConsuming();
                HiLog.info(label, "任务3执行完成");
            }
        });
        HiLog.info(label, "任务3分发完成");
    }

    private void asyncDispatch() {
        TaskDispatcher taskDispatcher = getGlobalTaskDispatcher(
            TaskPriority.DEFAULT);

        HiLog.info(label, "任务1即将分发");
        taskDispatcher.asyncDispatch(new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务1开始执行");
                timeConsuming();
                HiLog.info(label, "任务1执行完成");
            }
        });
        HiLog.info(label, "任务1分发完成");

        HiLog.info(label, "任务2即将分发");
        taskDispatcher.asyncDispatch(new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务2开始执行");
                timeConsuming();
                HiLog.info(label, "任务2执行完成");
            }
        });
        HiLog.info(label, "任务2分发完成");

        HiLog.info(label, "任务3即将分发");
        taskDispatcher.asyncDispatch(new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务3开始执行");
                timeConsuming();
                HiLog.info(label, "任务3执行完成");
            }
        });
        HiLog.info(label, "任务3分发完成");
    }

    private void delayDispatch() {
        TaskDispatcher taskDispatcher = getGlobalTaskDispatcher(
            TaskPriority.DEFAULT);

        calendar.setTimeInMillis(System.currentTimeMillis());
        HiLog.info(label, "任务即将分发:%{public}s",
            simpleDateFormat.format(calendar.getTime()));
        taskDispatcher.delayDispatch(new Runnable() {
            @Override
            public void run() {
                calendar.setTimeInMillis(System.currentTimeMillis());
                HiLog.info(label, "任务开始执行:%{public}s",
                    simpleDateFormat.format(calendar.getTime()));
                timeConsuming();
                calendar.setTimeInMillis(System.currentTimeMillis());
                HiLog.info(label, "任务执行完成:%{public}s",
                    simpleDateFormat.format(calendar.getTime()));
            }
        }, 100);
        calendar.setTimeInMillis(System.currentTimeMillis());
        HiLog.info(label, "任务分发完成:%{public}s",
            simpleDateFormat.format(calendar.getTime()));
    }

    private void asyncGroupDispatch() {
        TaskDispatcher taskDispatcher = createParallelTaskDispatcher(
            "PTD1", TaskPriority.DEFAULT);

        Group group = taskDispatcher.createDispatchGroup();

        taskDispatcher.asyncGroupDispatch(group, new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务1开始执行");
                timeConsuming();
                HiLog.info(label, "任务1执行完成");
            }
        });

        taskDispatcher.asyncGroupDispatch(group, new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务2开始执行");
                timeConsuming();
                HiLog.info(label, "任务2执行完成");
            }
        });

        taskDispatcher.groupDispatchNotify(group, new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "组中任务执行完成");
            }
        });
    }

    private void revoke() {
        TaskDispatcher taskDispatcher = getGlobalTaskDispatcher(
            TaskPriority.DEFAULT);

        HiLog.info(label, "任务即将分发");
        Revocable revocable = taskDispatcher.delayDispatch(new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务开始执行");
                timeConsuming();
                HiLog.info(label, "任务执行完成");
            }
        }, 100);
        HiLog.info(label, "任务分发完成");

        if (revocable.revoke())
            HiLog.info(label, "任务取消成功");
        else
            HiLog.info(label, "任务取消失败");
    }

    private void syncDispatchBarrier() {
        TaskDispatcher taskDispatcher = createParallelTaskDispatcher(
            "PTD1", TaskPriority.DEFAULT);

        Group group = taskDispatcher.createDispatchGroup();

        taskDispatcher.asyncGroupDispatch(group, new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务1开始执行");
                timeConsuming();
                HiLog.info(label, "任务1执行完成");
            }
        });

        taskDispatcher.asyncGroupDispatch(group, new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务2开始执行");
                timeConsuming();
                HiLog.info(label, "任务2执行完成");
            }
        });

        HiLog.info(label, "屏障任务即将设置");
        taskDispatcher.syncDispatchBarrier(new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "屏障任务开始执行");
                timeConsuming();
                HiLog.info(label, "屏障任务执行完成");
            }
        });
        HiLog.info(label, "屏障任务设置完成");
    }

    private void asyncDispatchBarrier() {
        TaskDispatcher taskDispatcher = createParallelTaskDispatcher(
            "PTD1", TaskPriority.DEFAULT);

        Group group = taskDispatcher.createDispatchGroup();

        taskDispatcher.asyncGroupDispatch(group, new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务1开始执行");
                timeConsuming();
                HiLog.info(label, "任务1执行完成");
            }
        });

        taskDispatcher.asyncGroupDispatch(group, new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "任务2开始执行");
                timeConsuming();
                HiLog.info(label, "任务2执行完成");
            }
        });

        HiLog.info(label, "屏障任务即将设置");
        taskDispatcher.asyncDispatchBarrier(new Runnable() {
            @Override
            public void run() {
                HiLog.info(label, "屏障任务开始执行");
                timeConsuming();
                HiLog.info(label, "屏障任务执行完成");
            }
        });
        HiLog.info(label, "屏障任务设置完成");
    }

    private void applyDispatch() {
        TaskDispatcher taskDispatcher = createParallelTaskDispatcher(
            "PTD1", TaskPriority.DEFAULT);

        taskDispatcher.applyDispatch((index) -> {
            HiLog.info(label, "任务开始执行:%{public}d", index);
            timeConsuming();
            HiLog.info(label, "任务执行完成:%{public}d", index);
        }, 3);
    }
}

运行效果如下图所示:

 
             

4 事件处理

EventHandler是一种从一个线程向另一个线程,投递InnerEvent事件或Runnable任务的线程通信机制。

每一个EventHandler都和特定线程的EventRunner绑定,并且该线程内部有一个事件队列。EventHandler可以投递特定的InnerEvent事件或Runnable任务到这个事件队列。

EventRunner从事件队列中循环地取出事件:

一般而言,EventHandler有两个主要作用:

例程:Event

...\Event\entry\src\main\resources\base\graphic\background_button.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:shape="oval">
    <solid ohos:color="#00a2e8"/>
</shape>

...\Event\entry\src\main\resources\base\layout\ability_main.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:alignment="center"
    ohos:orientation="vertical"
    ohos:background_element="#000000">

    <Text
        ohos:id="$+id:txt"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:text="珍惜时间"
        ohos:text_size="40fp"
        ohos:text_color="#ffffff"
        />

    <Button
        ohos:id="$+id:btn"
        ohos:height="80vp"
        ohos:width="80vp"
        ohos:top_margin="50vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="开始"
        ohos:text_size="26fp"
        ohos:text_color="#ffffff"
        />

</DirectionalLayout>

...\Event\entry\src\main\java\com\minwei\event\slice\MainAbilitySlice.java

class ClockEventHandler extends EventHandler {
    private Text text;

    public ClockEventHandler(EventRunner eventRunner, Text text) {
        super(eventRunner);

        this.text = text;
    }

    @Override
    protected void processEvent(InnerEvent event) {
        super.processEvent(event);

        if (event.eventId == 100)
            text.setText(new SimpleDateFormat("H:mm:ss")
                .format(event.object));
    }
}

public class MainAbilitySlice extends AbilitySlice {
    private EventRunner eventRunner;
    private ClockEventHandler eventHandler;

    private TaskDispatcher taskDispatcher;

    private Button button;
    private boolean stop = false;

    @Override
    public void onStart(Intent intent) {
        ...
        eventRunner = EventRunner.getMainEventRunner();
        eventHandler = new ClockEventHandler(eventRunner,
            (Text)findComponentById(ResourceTable.Id_txt));

        taskDispatcher = createParallelTaskDispatcher(
            "PTD1", TaskPriority.DEFAULT);

        button = (Button)findComponentById(ResourceTable.Id_btn);
        button.setClickedListener(component -> {
            if (button.getText().equals("开始") ||
                button.getText().equals("继续")) {
                ((ShapeElement)button
                    .getBackgroundElement())
                    .setRgbColor(new RgbColor(255, 127, 39));
                button.setText("暂停");
                stop = false;

                taskDispatcher.asyncDispatch(new Runnable() {
                    @Override
                    public void run() {
                        while (!stop) {
                            eventHandler.sendEvent(InnerEvent.get(
                                100, Calendar.getInstance().getTime()));
                            try { Thread.sleep(1000); }
                            catch (InterruptedException exception) {}
                        }
                    }
                });
            }
            else {
                ((ShapeElement)button
                    .getBackgroundElement())
                    .setRgbColor(new RgbColor(34, 177, 76));
                button.setText("继续");
                stop = true;
            }
        });
    }
    ...
}

运行效果如下图所示:

更多精彩,敬请期待……


达内集团C++教学部 2021年9月21日