Use of multithreading in Java projects

Posted by jagguy on Sun, 30 Jan 2022 22:49:01 +0100

1, Thread pool creation

If you need to use multithreading in your project, be sure to create a thread pool first. Because the thread pool can achieve thread reuse and save the overhead of repeated creation and destruction. Improve performance. Just like the database connection pool used in normal projects.

First, let's look at the method of creating a process pool:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

int corePoolSize, number of core threads

int maximumPoolSize, maximum number of threads

long keepAliveTime: the survival time of the thread when there is no task

Timeunit

BlockingQueue < runnable > workqueue is a blocking queue used to store tasks waiting to be executed. The selection of this parameter is also very important and will have a significant impact on the running process of the thread pool. Generally speaking, the blocking queue here has the following options:

ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;

ThreadFactory threadFactory, a thread factory, is mainly used to create threads

RejectedExecutionHandler handler indicates the policy when rejecting processing tasks. There are four values: ThreadPoolExecutor Abortpolicy: discards the task and throws a RejectedExecutionException exception.    ThreadPoolExecutor.DiscardPolicy: also discards tasks without throwing exceptions.      ThreadPoolExecutor.DiscardOldestPolicy: discard the task at the top of the queue and try to execute the task again (repeat this process)

ThreadPoolExecutor.CallerRunsPolicy: this task is handled by the calling thread

According to the above method, we can start to create our thread pool

//Create bounded queues to prevent memory overflow
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(1024);
#Using the namedthreadfactory of hutool, hutool is a very useful collection of tool classes
ThreadFactory threadFactory = new NamedThreadFactory("test",false);
ThreadPoolExecutor es = new ThreadPoolExecutor(
                8,
                16,
                1, TimeUnit.SECONDS,
                workQueue,threadFactory);

This completes the creation of my thread pool.

2, Select the creation of thread according to the business

If there is a return value, implement the Callable interface; otherwise, implement the Runnable interface

Now suppose we have a business that needs to return results, how to implement it? Next, go directly to the code:

public static class Task implements Callable<String>{

        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
        @Override
        public String call() throws Exception {
           
            return Thread.currentThread().getName();
        }
    }

In this way, even if the Callable interface is implemented, we certainly need to process the business in normal business, so we must accept parameters. Therefore, our class must also add a constructor to receive parameters. The code is as follows:

public static class Task2 implements Callable<String>{

        private String name;

        private int age;

        public Task2(String name, int age) {
            this.name = name;
            this.age = age;
        }

        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
        @Override
        public String call() throws Exception {
            System.out.println("name = " + name);
            System.out.println("age = " + age);
            //Processing business logic
            //Return processing results
            return Thread.currentThread().getName();
        }
    }

Note: the parameters returned by callable < > can be customized

For example: callable < student > returns an object; callable < string > returns a string

III. complete code

package com.xingli.springlearningdemo.stream;

import cn.hutool.core.thread.NamedThreadFactory;

import java.util.*;
import java.util.concurrent.*;

/**
 * description: streamTest <br>
 *
 * @date: 2021/6/11 0011 1:35 PM < br >
 * @author: William <br>
 * version: 1.0 <br>
 */

public class streamTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        List<Future<String>> futureList = new ArrayList<>();
        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(1024);
        ThreadFactory threadFactory = new NamedThreadFactory("test",false);
        ThreadPoolExecutor es = new ThreadPoolExecutor(8,16,3, TimeUnit.SECONDS,workQueue,threadFactory);
        for (int i = 0; i < 100; i++) {
            try{
                futureList.add(es.submit(new Task()));
                System.out.println("Current queued threads:= " + es.getQueue().size());
                System.out.println("Number of currently active threads:= " + es.getActiveCount());
                System.out.println("===============================");
            }catch (Exception e){
                System.out.println("abnormal");
            }
        }
        es.shutdown();
        System.out.println("Thread end===============================");
        for (Future<String> stringFuture : futureList) {
            System.out.println(stringFuture.get().toString());
        }
    }


    public static class Task implements Callable<String>{

        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
        @Override
        public String call() throws Exception {
            Thread.sleep(10);
            return Thread.currentThread().getName();
        }
    }

    public static class Task2 implements Callable<String>{

        private String name;

        private int age;

        public Task2(String name, int age) {
            this.name = name;
            this.age = age;
        }

        /**
         * Computes a result, or throws an exception if unable to do so.
         *
         * @return computed result
         * @throws Exception if unable to compute a result
         */
        @Override
        public String call() throws Exception {
            System.out.println("name = " + name);
            System.out.println("age = " + age);
            return Thread.currentThread().getName();
        }
    }

}

 

Topics: Java Multithreading thread pool