手动实现kt(java)同步工作流和异步工作流

前言

项目开发中可能会出现需要多个同步任务串行执行,或者多个异步任务都执行完毕再执行下一步的

其实如果用kotlin的协程的话,可以很方便的完成,但如果不想用kt写或者引入协程库的话,就可以用下面两个工具类

正文

同步串行执行任务,使用链表结构

import com.lt.androidkj.utils.mlistener.EmptyListener
import com.lt.androidkj.utils.mlistener.FunctionFlowBeanListener

/**
 * creator: lt  2019/11/26--10:40    lt.dygzs@qq.com
 * effect : 方法顺序运作工具类,使用链表数据结构
 * warning:
 */
class FunctionFlow {
    private var first: LinkedBean? = null//头结点
    private var last: LinkedBean? = null//尾结点
    private var finishListener: EmptyListener? = null//全部事件结束的回调

    /**
     * 顺序的添加任务
     * @param id 正常情况下没什么用,但是next(n)的时候跳转到指定的id上
     * @param function 执行的任务,回调里有个FunctionFlowBean类型的参数,调用他的invoke()可以执行后面的方法
     */
    fun add(id: Int = 0, function: FunctionFlowBeanListener): FunctionFlow {
        //第一次添加
        if (first == null) {
            first = LinkedBean(function, id)
            last = first
            return this
        }
        //以后再添加
        val functionFlowBean = LinkedBean(function, id)
        last!!.next = functionFlowBean
        last = functionFlowBean
        return this
    }

    /**
     * 开始顺序执行所有任务,后面的任务完成后调用.invoke()即可开始下一个任务
     * @param finishListener 全部任务完成后触发,可以不传
     */
    @JvmOverloads
    fun start(finishListener: EmptyListener? = null) {
        val first = first ?: return
        this.finishListener = finishListener
        //设置尾结点,保证链式调用中,参数不为空
        val noFunctionFlowBean = LinkedBean({}, -1)
        last!!.next = noFunctionFlowBean
        last = noFunctionFlowBean
        //开始第一个任务
        first.function(first.next!!)
    }

    /**
     * 链表bean
     */
    inner class LinkedBean(
            val function: FunctionFlowBeanListener,
            val id: Int,
            var next: LinkedBean? = null
    ) {
        /**
         * 开始下一个任务
         * @param skip -1表示下一个任务,大于0表示跳到id为n的任务
         */
        @JvmOverloads
        fun ok(skip: Int = -1) {
            if (skip < 0) {
                //执行下一个任务
                val next = next
                if (next == null) {
                    finishListener?.invoke()
                    return
                }
                function(next)
            } else {
                //跳到id为n的任务
                var next: LinkedBean? = this
                while (true) {
                    if (next == null) {//判断如果后续没有方法,则走finish
                        finishListener?.invoke()
                        return
                    }
                    if (next.id == skip) {//如果下一个任务的id和指定的id相同,则调用下一个方法
                        next.function(next.next!!)
                        return
                    }
                    next = next.next//如果上面两个条件都不符合,则判断下一个任务
                }
            }
        }
    }
}


typealias EmptyListener = () -> Unit
typealias FunctionFlowBeanListener = (FunctionFlow.LinkedBean) -> Unit
typealias FunctionStartsBeanListener = (FunctionStarts.EndBean) -> Unit

使用方式:

异步并行执行任务,也是使用的链表结构:

import com.lt.androidkj.utils.ThreadPool.ThreadType.*
import com.lt.androidkj.utils.mlistener.EmptyListener
import com.lt.androidkj.utils.mlistener.FunctionStartsBeanListener

/**
 * creator: lt  2019/12/23--17:15    lt.dygzs@qq.com
 * effect : 同时执行所有任务,全部执行完成后调用完成的回调,可以指定线程,默认子线程
 * warning:
 */
class FunctionStarts {
    private val map = LinkedHashMap<EndBean, ThreadPool.ThreadType>()

    /**
     * 添加任务,并指定该任务所运行的线程模式
     */
    fun add(type: ThreadPool.ThreadType = CACHE, function: FunctionStartsBeanListener): FunctionStarts {
        map[EndBean(function)] = type
        return this
    }

    /**
     * 开始所有任务,并在全部完成后执行回调,且不保证运行在哪个线程中
     */
    fun start(finishListener: EmptyListener) {
        map.forEach { (bean, type) ->
            when (type) {
                SINGLE -> ThreadPool::submitToSingleThreadPool
                CACHE -> ThreadPool::submitToCacheThreadPool
                FIXED -> ThreadPool::submitToTimeThreadPoolNoTime
                MAIN -> ::post
            }{
                bean.endListener = {
                    synchronized(this@FunctionStarts) {
                        map.remove(bean)
                        if (map.size == 0)
                            finishListener()
                    }
                }
                bean.run(bean)
            }
        }
    }

    /**
     * 调用该类的end方法,表示任务已经执行完毕
     * @param run 提交的任务
     */
    class EndBean(val run: FunctionStartsBeanListener) {
        //任务结束的回调
        var endListener: EmptyListener? = null

        /**
         * 表示任务已经执行完毕
         */
        fun ok() {
            endListener?.invoke()
        }
    }
}


/**
     * 线程类型
     */
    enum class ThreadType {
        /**
         * 单例线程,选择这种方式会按照启动的先后顺序串行执行
         */
        SINGLE,
        /**
         * 缓存线程池,选择这种方式会和其他任务并行执行,且无上限
         */
        CACHE,
        /**
         * 固定长度的线程池,达到设定的线程数量后,后面的任务等待空闲线程执行完毕后再执行
         */
        FIXED,
        /**
         * 跑在主线程中
         */
        MAIN
    }
::post实现方式如下
    val handler=Handler()
    fun post(listener:EmptyListener){
        handler.post(listener)
    }

其他的submitXXX都是提交到线程池,类似于如下
val singleThreadExecutor = Executors.newSingleThreadExecutor()//可以自己搜索如何创建或自定义线程池
    fun submitToSingleThreadPool(runnable: EmptyListener): Future<*> =
        singleThreadExecutor.submit(runnable)

使用方式:

而且还能联合使用来应对复杂需求,比如

先按照顺序弹两个弹窗(关闭前一个在打开下面的),然后请求三个异步接口(但要求第二个和第三个要按顺序执行),接口全部成功后在按照顺序弹两个弹窗

FunctionFlow()
                .add {
                    showSelectPhotoDialog(1) { arr ->
                        it.ok()
                    }
                }
                .add {
                    showSelectPhotoDialog(1) { arr ->
                        it.ok()
                    }
                }
                .add {
                    //执行异步网络请求
                    FunctionStarts()
                            .add {
                                http1 {
                                    it.ok()
                                }
                            }
                            .add(ThreadPool.ThreadType.SINGLE) {
                                http2 {
                                    it.ok()
                                }
                            }
                            .add(ThreadPool.ThreadType.SINGLE) {
                                http3 {
                                    it.ok()
                                }
                            }
                            .start {
                                print("异步接口执行完毕")
                                it.ok()
                            }
                }
                .add {
                    showSelectPhotoDialog(1) { arr ->
                        it.ok()
                    }
                }
                .add {
                    showSelectPhotoDialog(1) { arr ->
                        it.ok()
                    }
                }
                .start {
                    print("任务全部执行完成")
                }

对Kotlin或KMP感兴趣的同学可以进Q群 101786950

如果这篇文章对您有帮助的话

可以扫码请我喝瓶饮料或咖啡(如果对什么比较感兴趣可以在备注里写出来)

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
前 言 1 1 概 述 2 1.1 选题背景 2 1.2 组织结构 2 2 所用相关技术和方法 3 2.1 工作流 3 2.1.1 什么叫工作流 3 2.1.2 工作流发展 3 2.1.3 工作流的优点 3 2.2 MVC工作模式 4 2.2.1 MVC设计思想 4 2.2.2 MVC的具体实现 5 2.2.3 MVC的不足 6 2.3 JSP技术介绍 6 2.3.1 JSP的运行原理 7 2.3.2 JSP的生命周期 8 2.3.3 Servlet和JavaBean技术介绍 8 2.3.4 Java 虚拟机 9 2.3.5 JSP访问SQL Server 2000数据库 9 2.4 数据库后台环境配置 10 2.5 系统开发工具简介 10 2.5.1 Dr eamweaver 10 2.5.2 MyEclipse 10 2.5.3 Tomcat 11 2.5.4 SQL Server2000 11 2.5.5 chs_sql2ksp3 12 3 系统需求分析 13 3.1 系统功能分析 13 3.2 系统性能分析 13 3.3 系统方案的确定和评价 13 4 系统总体设计 15 4.1 系统层次模块图 15 4.1.1 营业厅模块 15 4.1.2 收费管理模块 16 4.2 系统数据流程图 16 4.3 数据表设计 18 5 详细设计及编码 21 5.1 编写JAVABEAN 21 5.2 营业厅实现函数 21 5.3 收费厅主要的实现函数 22 5.4 JAVABEAN主要实现模块 22 5.4.1 中文字符格式的转换模块(Stringto.java) 22 5.4.2 自动生成验证码(Ran.java) 22 5.4.3 数据库的连接(ConnectionFactory.java) 23 5.4.4 数据库连接的关闭(DatabaseUtils.java)--只提供接口 23 5.4.5 密码修改模块(Common_fuction.java) 24 5.4.6 时间格式转换(timeBean.java) 24 5.4.7 数据统计(counthander.java) 25 5.4.8 营业厅的接口(luruaction.java) 27 5.4.9 营业厅的主要函数实现(luruhander.java) 28 5.4.10 收费厅的主要函数接口 32 5.5 管理员登陆模块 33 5.5.1 管理员登录 33 5.6 营业厅管理模块 36 5.6.1 Left.jsp页面 36 5.6.2 Work.jsp 40 5.6.3 customerlistinfo.jsp 41 5.6.4 allinfo.jsp 41 5.7 收费厅管理模块 42 5.7.1 Left.jsp 42 5.7.2 Work.jsp 43 5.7.3 Customerlistinfo.jsp 43 5.7.4 gongdan.jsp 43 6 系统测试与维护 45 6.1 测试目的 45 6.2 测试环境 45 6.3 系统测试 45 6.4 系统维护 45 7 开发难点与技术 46 7.1 主要程序实现的代码描述 46 7.1.1 验证码的自动生成 46 7.1.2 生成WORD工单 46 7.1.3 以一定的时间刷新页面 47 7.1.4 JSP中文问题的解决 47 7.2 在程序编码过程遇到的主要问题: 48 7.3 代码编写风格 49 7.4 我的不足: 49 结束语 50 致 谢 50
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值