Java多线程_Java监控线程池及线程池扩展

1,010 阅读2分钟

「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

Java监控线程池

ThreadPoolExecutor提供了一组方法用于监控线程池。

int getActiveCount() 获得线程池中当前活动线程的数量。

long getCompletedTaskCount() 返回线程池完成任务的数量。

int getCorePoolSize() 线程池中核心线程的数量。

int getLargestPoolSize() 返回线程池曾经达到的线程的最大数。

int getMaximumPoolSize() 返回线程池的最大容量。

int getPoolSize() 当前线程池的大小。

BlockingQueue getQueue() 返回阻塞队列。

long getTaskCount() 返回线程池收到的任务总数。

package com.wkcto.threadpool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 监控线程池
 */
public class Test05 {
    public static void main(String[] args) throws InterruptedException {
        //先定义任务
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getId() + " 编号 的线程开始执行: " + System.currentTimeMillis());
                try {
                    Thread.sleep(10000);    //线程睡眠20秒,模拟任务执行时长
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        //定义线程池
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(2, 5, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());

        //向线程池提交30个任务
        for (int i = 0; i < 30; i++) {
            poolExecutor.submit(r);
            System.out.println("当前线程池核心线程数量: " + poolExecutor.getCorePoolSize() + ", 最大线程数:" + poolExecutor.getMaximumPoolSize() + ",当前线程池大小:" + poolExecutor.getPoolSize() + ",活动线程数量:" + poolExecutor.getActiveCount()+ ",收到任务数量:" + poolExecutor.getTaskCount() + ",完成任务数: " + poolExecutor.getCompletedTaskCount() + ",等待任务数:" + poolExecutor.getQueue().size()) ;
            TimeUnit.MILLISECONDS.sleep(500);
        }

        System.out.println("-----------------------------------------------");
        while ( poolExecutor.getActiveCount() >= 0 ){
            System.out.println("当前线程池核心线程数量: " + poolExecutor.getCorePoolSize() + ", 最大线程数:" + poolExecutor.getMaximumPoolSize() + ",当前线程池大小:" + poolExecutor.getPoolSize() + ",活动线程数量:" + poolExecutor.getActiveCount()+ ",收到任务数量:" + poolExecutor.getTaskCount() + ",完成任务数: " + poolExecutor.getCompletedTaskCount() + ",等待任务数:" + poolExecutor.getQueue().size()) ;
            Thread.sleep(1000);
        }
    }

}

Java线程池扩展

有时需要对线程池进行扩展,如在监控每个任务的开始和结束时间,或者自定义一些其他增强的功能。

ThreadPoolExecutor线程池提供了两个方法:

● protected void afterExecute(Runnable r, Throwable t)

● protected void beforeExecute(Thread t, Runnable r)

在线程池执行某个任务前会调用beforeExecute()方法,在任务结束后(任务异常退出)会执行afterExecute()方法。

查看ThreadPoolExecutor源码,在该类中定义了一个内部类Worker, ThreadPoolExecutor线程池中的工作线程就是Worker类的实例, Worker实例在执行时会调用beforeExecute()与 afterExecute()方法。

package com.wkcto.threadpool;

import com.wkcto.produerstack.MyStack;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 扩展线程池
 */
public class Test06 {
    //定义任务类
    private static class  MyTask implements  Runnable{
         String name;

        public MyTask(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            System.out.println(name + "任务正在被线程 " + Thread.currentThread().getId() + " 执行");
            try {
                Thread.sleep(1000);     //模拟任务执行时长
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        //定义扩展线程池, 可以定义线程池类继承ThreadPoolExecutor,在子类中重写beforeExecute()/afterExecute()方法
        //也可以直接使用ThreadPoolExecutor的内部类
        ExecutorService executorService = new ThreadPoolExecutor(5, 5, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>() ){
            //在内部类中重写任务开始方法
            @Override
            protected void beforeExecute(Thread t, Runnable r) {
                System.out.println(t.getId() + "线程准备执行任务: " + ((MyTask)r).name);
            }

            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                System.out.println( ((MyTask)r).name + "任务执行完毕");
            }

            @Override
            protected void terminated() {
                System.out.println("线程池退出");
            }
        };

        //向线程池中添加任务
        for (int i = 0; i < 5; i++) {
            MyTask task = new MyTask("task-" + i);
            executorService.execute(task);
        }

        //关闭线程池
        executorService.shutdown();     //关闭线程池仅仅是说线程池不再接收新的任务 , 线程池中已接收的任务正常执行完毕
    }
}