写点什么

Java 自定义异步功能实践

用户头像
FunTester
关注
发布于: 13 分钟前

前面我们提到线程池处理批量接口请求实践但是在语法上比较复杂,还需要进行线程间的同步,也需要一定的 Java 知识,最近在学习 Golang 语言时,感觉 go 关键字十分高效,只要是想异步执行的方法,只需在前面添加 go 关键字即可。


如果 Java 也能实现一个类似 go 的关键字,那该多好啊!

思路

Java 本身也是支持闭包的,通过闭包重建一个java.lang.Runnable的匿名实现类,然后创建线程去执行对应的方法,应该是可以实现简单异步功能。


既然 Java 都能支持,那 Groovy 肯定也有解决方案了,至少可以直接用 Java 的方案。


几种语言的闭包使用可以参考

实践

思路比较简单,下面分享一下实践过程。

Java

不同于其他语言,Java 闭包方法根据不同的参数、返回值有不同的实现类。这个地方有点烦,不够灵活。我试了java.util.function下面的多个实现类,最终选择了java.util.function.Supplier,原因是这个实现类没有参数,但是需要一个返回值。


There is no requirement that a new or distinct result be returned each time the supplier is invoked.


代码和使用方式如下:


package com.funtest.javatest;
import com.funtester.frame.SourceCode;
import java.util.function.Supplier;
public class Sync extends SourceCode {
public static void main(String[] args) { sync(() -> { sleep(0.1); output("tester"); return DEFAULT_CHARSET; }); output("FunTester"); }
public static void sync(Supplier f) { new Thread(() -> { f.get(); }).start(); }
}
复制代码


控制台输出:


INFO-> main 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16INFO-> main FunTesterINFO-> Thread-1 tester
Process finished with exit code 0
复制代码


这里先不展示 Groovy 如何使用了。后面有更精彩的。

Groovy

Groovy 语法相当简单,用一个groovy.lang.Closure解决所有问题。


代码和使用方式如下:


import com.funtester.frame.SourceCode
class Sync extends SourceCode {
public static void main(String[] args) {
sync { sleep(0.2) output(320) } output("FunTester")
}

static void sync(Closure f) { new Thread(f()).start() }}
复制代码


控制台输出:


INFO-> main 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16INFO-> main FunTesterINFO-> Thread-1 tester
Process finished with exit code 0
复制代码


可以看出 Groovy 语法是非常简单的,已经非常接近 Golang 语言 go 关键字的体验了,仅仅从语法上,性能上的问题以后会再讨论。

线程池升级

因为 Golang 语言有自己的 goroutine 管理器,加上 Golang 特性,所以不是用很担心创建过多的协程消耗更多资源。但是 Java 还是要考虑一下的,为了解决测试过程中创建过多线程导致异常出现,我用线程池解决这个问题。通过将闭包中的方法包装成java.lang.Runnable对象,丢给线程池去执行。


封装方法如下:


    /**     * 异步执行某个代码块     * Java调用需要return,Groovy也不需要,语法兼容     *     * @param f     */    public static void fun(Supplier f) {        Runnable runnable = new Runnable() {            @Override            public void run() {                f.get();            }        };        ThreadPoolUtil.executeSync(runnable);    }
复制代码


这里我选用了 Java 的语法,为什么不用 Groovy 的方法封装呢?因为 Groovy 完全兼容了 Java 的语法而不失去 Groovy 自己的特性。


下面演示一下 Java 如何使用:


public class FunT extends FunLibrary {
public static void main(String[] args) {
fun(()->{ sleep(0.1); output("FunTester"); return null; }); output("fds"); ThreadPoolUtil.shutFun() } }
复制代码


优先于 Java 语法,需要多写一些 code,这个我目前解决方案是通过Intellij自带的Live Templates输入代码模板解决。如图:



下面演示一下 Groovy 如何使用:


    public static void main(String[] args) {
fun { sleep(0.2) output(320) } output("FunTester") ThreadPoolUtil.shutFun() }
复制代码


同样我们可以使用Intellij自带的Live Templates输入代码模板,不再展示了。


简直如丝般顺滑。


控制台输出:


INFO-> main 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16INFO-> main FunTesterINFO-> FT-1 320
Process finished with exit code 0
复制代码


这里我自定义了线程的名字,方法如下:


    /**     * 自定义{@link ThreadFactory}对象     * @return     */    static ThreadFactory getFactory() {        if (FunFactory == null) {            synchronized (ThreadPoolUtil.class) {                if (FunFactory == null) {                    FunFactory = new ThreadFactory() {
@Override Thread newThread(Runnable runnable) { Thread thread = new Thread(runnable); def increment = threadNum.getAndIncrement() def name = increment < 10 ? "00" + increment : increment < 100 ? "0" + increment : Constant.EMPTY + increment thread.setName("FT-" + name); return thread; } } } } } return FunFactory }
复制代码

多线程同步

如果遇到有多线程同步需求,那么依旧使用java.util.concurrent.Phaser来满足需求。封装方法如下:


    /**     * 异步执行代码块,使用{@link Phaser}进行多线程同步     *     * @param f     * @param phaser     */    public static void fun(Supplier f, Phaser phaser) {        Runnable runnable = new Runnable() {            @Override            public void run() {                try {                    phaser.register();                    f.get();                } catch (Exception e) {                    logger.warn("执行异步方法时发生错误!", e);                } finally {                    phaser.arriveAndDeregister();                }                            }        };        ThreadPoolUtil.executeSync(runnable);    }
复制代码

Have Fun ~ Tester !

发布于: 13 分钟前阅读数: 2
用户头像

FunTester

关注

公众号:FunTester,650+原创,欢迎关注 2020.10.20 加入

Have Fun,Tester! 公众号FunTester,坚持原创文章的测试人。 FunTester测试框架作者,DCS_FunTester分布式性能测试框架作者。

评论

发布
暂无评论
Java自定义异步功能实践