日常调戏Java:方法的分步执行

从最初开始学习Java编程开始,就产生一个认知:Java方法的执行通常是一步到位的,不能被打断,除非异常、程序终止或线程调度。因此,通常如果需要两个过程交叉进行并通信的话,采用多线程+线程同步的方式来进行。然而,线程切换和同步的开销有时是不可忽视的,那么有没有其他方式来处理这个问题呢?比如说,过程的调用者让一个过程执行到一半停下来,接着去做其他事,然后再回过来继续执行没有执行完的过程。例如这个过程:

Integer test0(Integer i) {
    System.out.println("执行操作 1");
    //让步 停止执行
    System.out.println("执行操作 2");
    //让步 停止执行
    System.out.println("执行操作 3");
    return i + 1;
}

在这个过程里让每一个步骤执行完停下,让调用者去做其他事情。本文就给出一种简单的实现方式。

1. 示例

先来看一个例子,这里模拟test方法和main交叉执行的情况。

public class Demo {

    public static void main(String[] args) {
        InterruptableProcedure<Integer, Integer> procedure = InterruptableProcedure.create((scheduler) -> (i) -> test(scheduler, i));
        /* 也可以写成这个样子
        InterruptableProcedure<Integer, Integer> procedure = InterruptableProcedure.create((scheduler) -> (i) -> {
            System.out.println("执行操作 1");
            return scheduler.yield(() -> {
                System.out.println("执行操作 2");
                return scheduler.yield(() -> {
                    System.out.println("执行操作 3");
                    return i + 1;
                });
            });
        });
        */

        procedure.start(1);          //这里只传递参数,不执行
        System.out.println("喝杯水");
        procedure.goNext();          //执行下一步
        System.out.println("睡一觉");
        procedure.goNext();          //执行下一步
        System.out.println("玩一会");
        procedure.goNext();          //执行下一步
        if (procedure.isEnd()) {     //判断是否结束
            int r = procedure.getValue();//取出返回值
            System.out.println("结束:" + r);
        }
    }

    public static Integer test(InterruptableProcedure<Integer, Integer>.Scheduler scheduler, Integer i) {
        System.out.println("执行操作 1");
        return scheduler.yield(() -> {//引入第一个中断点
            System.out.println("执行操作 2");
            return scheduler.yield(() -> {//引入第二个中断点
                System.out.println("执行操作 3");
                return i + 1;
            });
        });
    }
}

程序的打印输出如下:

喝杯水
执行操作 1
睡一觉
执行操作 2
玩一会
执行操作 3
结束:2

这里的goNext方法是执行到下一个scheduler.yield为止,也可以用goEnd方法直接执行完整个过程:

procedure.start(1);
System.out.println("喝杯水");
procedure.goNext();
System.out.println("睡一觉");
int x = procedure.goEnd();
System.out.println("结束:" + x);

打印的结果如下:

喝杯水
执行操作 1
睡一觉
执行操作 2
执行操作 3
结束:2

2. API功能介绍

  • InterruptableProcedure.start方法:起始方法,用于传递参数,重置状态,不执行实际过程。
  • InterruptableProcedure.goNext方法:执行实际过程的下一步(也就是到下一个scheduler.yield为止),如果没有下一步就抛出异常。
  • InterruptableProcedure.goEnd方法:从当前状态一直执行,直到整个过程结束。
  • InterruptableProcedure.isEnd方法:判断过程是否执行完。
  • InterruptableProcedure.getValue方法:获取过程的返回值。
  • Scheduler.yield方法:从当前过程中让步,参数为剩余要执行的过程。

3. 相关类的实现

interface Fun<T, R> extends Function<InterruptableProcedure<T, R>.Scheduler, Function<T, R>> {

}

class InterruptableProcedure<T, R> {
    private static final Supplier<?> EMPTY_FUN = () -> {
        throw new IllegalStateException("This procedure is end!");
    };
    private final Fun<T, R> originFun;  //原始完整过程
    private final Scheduler scheduler = new Scheduler();
    private T arg;
    private R result;
    private Supplier<R> intermediateFun;//中间过程,也是下一步要执行的过程

    InterruptableProcedure(Fun<T, R> originFun) {
        this.originFun = originFun;
    }

    public static <T, R> InterruptableProcedure<T, R> create(Fun<T, R> o) {
        return new InterruptableProcedure<>(o);
    }

    public void start(T t) {
        arg = t;
        intermediateFun = null;
        result = null;
    }

    public void goNext() {
        if (intermediateFun == null) {
            result = originFun.apply(scheduler).apply(arg);
            if (intermediateFun == null) {//处理方法中没有调用scheduler.yield的情况
                intermediateFun = (Supplier<R>) EMPTY_FUN;
            }
        } else {
            Supplier<R> temp = intermediateFun;
            result = intermediateFun.get();
            if (temp == intermediateFun) {//如果相等,表示intermediateFun没有更新,意味着整个过程已经执行完,
                intermediateFun = (Supplier<R>) EMPTY_FUN;
            }
        }
    }

    public boolean isEnd() {
        return intermediateFun == EMPTY_FUN;
    }

    public R getValue() {
        return result;
    }

    public R goEnd() {
        while (!isEnd()) {
            goNext();
        }
        return result;
    }

    public class Scheduler {
        public R yield(Supplier<R> supplier) {
            intermediateFun = supplier;
            return null;
        }
    }
}

4. 写在最后

本文所展示的代码仅用于学习,切勿用于项目中!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值