In the last installment of the Java Custom asynchronous functionality practice article, I designed a keyword, passed in a closure, and then asynchronously executed the code block in the closure. But in practice it gets a little more complicated. There were some problems with creating thread pools that execute asynchronous methods.

  • If the core value is greater than 1, the thread pool must be closed manually
  • If you create a thread pool core=0, you must set a non-zero workQueue
  • If the workQueue setting is too small to hold more tasks
  • If the workQueue setting is too large, no more threads can be created (only 1 thread is actually created)

After some thought in my life, I decided to use a daemon to solve this problem. See Creating a Java daemon thread.

Train of thought

For the thread pool to execute the asynchronous method, I used a fixed-length thread pool and set the number of threads to 16, since this scenario is mainly used for bulk script execution, so efficiency is a priority. Set the workQueue to 1 million (or 100,000), no difference currently in use.

How to take advantage of daemon features after the test, wait for the main thread to finish executing, and then reclaim resources.

To avoid waste, only enable this daemon when using asynchronous functionality.

Step by step to achieve

Creating a thread pool

The method is as follows:

    private static volatile ExecutorService funPool;
    
    /** * get asynchronous task connection pool *@return* /
    static ExecutorService getFunPool(a) {
        if (funPool == null) {
            synchronized (ThreadPoolUtil.class) {
                if (funPool == null) {
                    funPool = createFixedPool(Constant.POOL_SIZE);
                    daemon()
                }
            }
        }
        return funPool
    }
Copy the code

Creating a daemon thread

    /** * Execute daemon threads and close the thread pool * after the main method ends@return* /
    static boolean daemon(a) {
        def thread = new Thread(new Runnable() {

            @Override
            void run(a) {
                while (checkMain()) {
                    SourceCode.sleep(1.0)
                }
                ThreadPoolUtil.shutFun()
            }
        })
        thread.setDaemon(true)
        thread.setName("FT-D")
        thread.start()
        logger.info("Daemon thread :{} open!", thread.getName())
    }
Copy the code

Check whether the main thread is alive

    /** * Check whether the main thread is alive *@return* /
    static boolean checkMain(a) {
        def count = Thread.activeCount()
        def group = Thread.currentThread().getThreadGroup()
        def threads = new Thread[count]
        group.enumerate(threads)
        for (i in 0..<count) {
            if (threads[i].getName() == "main")
                return true
        }
        false
    }

Copy the code

test

The test script

We simply use the Groovy sugar times syntax to iterate over the closure contents from 0 to 20, and it to iterate over the index from 0 to 19.

    public static void main(String[] args) {
        20.times {
            def a = it as String
            fun{
                sleep(1.0)
                output(StringUtil.right("index:" + a, 10) + Time.getNow())
            }
        }

    }
Copy the code

The Java version of the following is easier to understand:

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            Integer a = i;
            fun(() -> {
                sleep(1.0);
                output(StringUtil.right("index:" + a, 10) + Time.getNow());
                return null; }); }}Copy the code

Console output

INFO->Main current user: oker, working directory: / Users/oker/IdeaProjects funtester/system coding format: utf-8, Mac OS X system version: 10.16
INFO->Main daemon thread :FT -d enabled!
INFO->FT-13 index:12 20211011182658
INFO->FT-3 index:2 20211011182658
INFO->FT-16 index:15 20211011182658
INFO->FT-14 index:13 20211011182658
INFO->FT-5 index:4 20211011182658
INFO->FT-4 index:3 20211011182658
INFO->FT-12 index:11 20211011182658
WARN->Ft-d asynchronous thread pool closed!
INFO->FT-10 index:9 20211011182658
INFO->FT-7 index:6 20211011182658
INFO->FT-2 index:1 20211011182658
INFO->FT-11 index:10 20211011182658
INFO->FT-8 index:7 20211011182658
INFO->FT-15 index:14 20211011182658
INFO->FT-1 index:0 20211011182658
INFO->FT-9 index:8 20211011182658
INFO->FT-6 index:5 20211011182658
INFO->FT-16 index:16 20211011182659
INFO->FT-7 index:19 20211011182659
INFO->FT-5 index:17 20211011182659
INFO->FT-12 index:18 20211011182659

Process finished with exit code 0

Copy the code

Thread synchronization

Multithreaded synchronization is still using Java. Util. Concurrent. The Phaser class, but with the parameter after a little damage to the original elegant syntax.

The Groovy version:

    public static void main(String[] args) {
        def phaser = new Phaser(1)
        20.times {
            def a = it as String
            fun {
                sleep(1.0)
                output(StringUtil.right("index:" + a, 10) + Time.getNow())
            } , phaser
        }
        phaser.arriveAndAwaitAdvance()
    }
Copy the code

It’s pretty comfortable to write this, but the compiler will give you an error, so ignore that, because the compiler doesn’t always get it right.

Java version:

    public static void main(String[] args) {
        Phaser phaser = new Phaser(1);
        for (int i = 0; i < 20; i++) {
            Integer a = i;
            fun(() -> {
                sleep(1.0);
                output(StringUtil.right("index:" + a, 10) + Time.getNow());
                return null;
            },phaser);
        }
        phaser.arriveAndAwaitAdvance();
    }
Copy the code

Console output:

INFO->Main current user: oker, working directory: / Users/oker/IdeaProjects funtester/system coding format: utf-8, Mac OS X system version: 10.16
INFO->Main daemon thread :FT -d enabled!
INFO->FT-11 index:10 20211011185814
INFO->FT-1 index:0 20211011185814
INFO->FT-5 index:4 20211011185814
INFO->FT-3 index:2 20211011185814
INFO->FT-16 index:15 20211011185814
INFO->FT-10 index:9 20211011185814
INFO->FT-7 index:6 20211011185814
INFO->FT-14 index:13 20211011185814
INFO->FT-9 index:8 20211011185814
INFO->FT-12 index:11 20211011185814
INFO->FT-15 index:14 20211011185814
INFO->FT-8 index:7 20211011185814
INFO->FT-6 index:5 20211011185814
INFO->FT-13 index:12 20211011185814
INFO->FT-2 index:1 20211011185814
INFO->FT-4 index:3 20211011185814
INFO->FT-3 index:16 20211011185815
INFO->FT-15 index:19 20211011185815
INFO->FT-7 index:18 20211011185815
INFO->FT-16 index:17 20211011185815
WARN->Ft-d asynchronous thread pool closed!

Process finished with exit code 0
Copy the code

You can see that the WARN-> FT -d asynchronous thread pool is closed! It was printed last, as expected.

Have Fun ~ Tester!

  • FunTester test framework architecture diagram
  • JMeter Chinese Operation Manual with a sense of time
  • 140 interview questions (UI, Linux, MySQL, API, security)
  • Graphic HTTP brain map
  • Share a Fiddler study bag
  • JVM command brain map for testing
  • The Definitive Guide to Java Performance
  • JSON based
  • Math.abs() returns negative value for absolute value
  • Moco framework interface hit ratio statistics practice
  • Discussion on assembly point and multi-stage synchronization in performance testing
  • 3d image of two-wave source interference is made by Python + Plotly
  • How does code review ensure software quality
  • How does automation select use cases