JStorm源码分析小贴士(一)进一步了解 AsyncLoopThread(草稿)

来源:互联网 发布:阿里云备案文件 编辑:程序博客网 时间:2024/06/05 19:56

Worker 的源代码中,我们发现有很多地方出现了AsyncLoopThread,下面我们来简单解读一下这个类的源码,并阐述该类的作用。

(一)继承体系


SmartThread 这个接口比较简单,仅仅定义了“灵活线程”所必须实现的方法,如下所示:

public interface SmartThread {    public void start();    public void join() throws InterruptedException;;    public void interrupt();    public Boolean isSleeping();    public void cleanup();}

(二)主要属性

AsyncLoopThread 包含两个主要成员:

Thread对象

RunnableCallback 对象,RunnableCallback类实现了JavaRunnable接口,所以它的本质是一个可在线程中执行的任务。除此之外,RunnableCallback类还实现了两个自定义接口,分别是CallbackShutdownable,如下所示:

虽然 RunnableCallback 是一个类,但是它在实现这三个接口时,没有填充任何实际逻辑:

public class RunnableCallback implements Runnable, Callback, Shutdownable {    @Override    public <T> Object execute(T... args) {        return null;    }    public void preRun() {    }    @Override    public void run() {    }    public void postRun() {    }    public Exception error() {        return null;    }    public Object getResult() {        return null;    }    public void shutdown() {    }    public String getThreadName() {        return null;    }}

(三)构造方法

AsyncLoopThread 类共有三个构造方法,它们都调用了 init()方法进行构造。

init() 方法接收的参数如下表所示:

参数名

类型

含义

afn

RunnableCallback

需要使用线程异步循环往复执行的任务

daemon

boolean

是否作为守护线程执行,默认值为 false

priority

int

线程的优先级,默认值为 Thread.NORM_PRIORITY

start

boolean

是否立刻启动该线程,默认值为 true

kill_fn

RunnableCallback

指定执行杀死任务的任务,默认值为 AsyncLoopDefaultKill 实例

init() 方法中,

private void init(RunnableCallback afn, boolean daemon, RunnableCallback kill_fn, int priority, boolean start) {        if (kill_fn == null) {            kill_fn = new AsyncLoopDefaultKill();        }        Runnable runnable = new AsyncLoopRunnable(afn, kill_fn);        thread = new Thread(runnable);        String threadName = afn.getThreadName();        if (threadName == null) {            threadName = afn.getClass().getSimpleName();        }        thread.setName(threadName);        thread.setDaemon(daemon);        thread.setPriority(priority);        thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {            @Override            public void uncaughtException(Thread t, Throwable e) {                LOG.error("UncaughtException", e);                JStormUtils.halt_process(1, "UncaughtException");            }        });        this.afn = afn;        if (start) {            thread.start();        }    }

1. 如果没有指定执行杀死任务的任务,那么默认创建一个 AsyncLoopDefaultKill来执行;

2. 构造一个 AsyncLoopRunnable 对象,它组合了要执行的主任务和负责杀死主任务的任务,作为一个组合任务;

3.  AsyncLoopRunnable 对象作为参数,新建一个线程,为其设定名字、是否为守护线程和优先级等基本属性;

4.  start 被置为true,那么将立刻启动该线程,执行组合任务。

那么 AsyncLoopRunnable 是如何组合主任务和负责杀死主任务的任务呢?

除了需要组合的两个任务作为成员之外, AsyncLoopRunnable 类中还包含两个原子布尔变量 shutdown shutdowned,分别用来记录关闭命令和记录已关闭状态,初始时均为false。使用一个时间戳lastTime记录当前时间。

该类实现了 Java Runnable接口,其run()方法实现如下:

 @Override    public void run() {        if (fn == null) {            LOG.error("fn==null");            throw new RuntimeException("AsyncLoopRunnable no core function ");        }        fn.preRun();        try {            while (!shutdown.get()) {                fn.run();                if (shutdown.get()) {                    shutdown();                    return;                }                Exception e = fn.error();                if (e != null) {                    throw e;                }                Object rtn = fn.getResult();                if (this.needQuit(rtn)) {                    shutdown();                    return;                }            }        } catch (Throwable e) {            if (shutdown.get()) {                shutdown();            } else {                LOG.error("Async loop died!!!" + e.getMessage(), e);                killFn.execute(e);            }        }    }

在一个循环体中,

1. 每次循环开始检查 shutdown 标志了解是否接受到停止指令,一旦检测到停止指令为真,立刻退出循环,任务结束;

2. 否则调用主任务的 run() 方法。之后再次检查 shutdown 标志,如果为真,那么执行shutdown()方法,并立刻返回,任务结束;

3. 否则继续执行,看主任务是否异常,如果是,抛出异常,并进行捕获,通过监督线程杀死主任务,任务结束;

4. 一切正常,查看主方法的结果,根据结果判断是否需要终止任务。

needQuit() 方法根据任务的返回值决定是否需要终止任务:

   if (rtn != null) {            long sleepTime = Long.parseLong(String.valueOf(rtn));            if (sleepTime < 0) {                return true;            } else if (sleepTime > 0) {                long now = System.currentTimeMillis();                long cost = now - lastTime;                long sleepMs = sleepTime * 1000 - cost;                if (sleepMs > 0) {                    JStormUtils.sleepMs(sleepMs);                    lastTime = System.currentTimeMillis();                } else {                    lastTime = now;                }            }        }        return false;

任务的返回值就是需要间隔的时间,如果休眠时间小于0,那么将要终止任务;否则,更新时间戳之后,线程阻塞若干时间后,继续执行。

(四)关键方法

由于实现了 SmartThread 接口,而本身又包含一个 Thread 对象,所以需要实现的方法都是通过Thread对象来实现的,这里不在赘述。

需要注意的是 cleanup() 的实现是调用主任务的 shutdown() 方法:

 @Override  public void cleanup() {        afn.shutdown();    }

(五)综述

从以上分析可以看出,AsyncLoopThread 类封装的是一个每隔一段时间执行一次的主任务,通过后台线程执行,同时设置一个配套的监督任务,用于在主任务发生异常时,中断执行线程。所以该类当做一个通用的简易定时任务类使用。

1 0
原创粉丝点击