在程序运行中,多线程运行时直接使用会涉及线程的频繁启用和销毁,这样会很占用资源,比如在通讯软件中,你和多个人聊天时,同时开启多个线程,过了一会不聊了假如这时关闭线程,那我过不久就又要聊天又开启线程,这样的频繁开启和销毁线程会很占用资源。如果是让线程空转呢,假设我很长时间不聊,空转的线程也会占用资源。为了解决这个问题我们就创建了线程池。

线程池由正在处理的线程,待处理的线程和临时处理的线程组成。正在处理的线程会一直存在直至处理完成,如果放入的任务多于线程池处理的线程数量,就会存放至线程池的阻塞队列中,处理完一个线程就从队列中按顺序拿出任务继续处理,临时处理线程时在线程池和队列都满的时候,用来处理加入的线程,这个有时间限制,当时间到了线程就会直接销毁无论有没有完成。

下面是我模拟的一个简易线程池:

public class ThreadPool {
    private List<Runnable> threadList=new ArrayList<>();//队列加核心处理线程
    private Lock lock=new ReentrantLock();
    private Condition isEmpty= lock.newCondition();
    int coreThreadNum;//核心线程数
    int maximumThread;//最大处理线程数
    int queueTread;//阻塞线程数
    List<WorkThread> workList=new ArrayList<>();//用于创建临时线程

    public ThreadPool(int coreThreadNum,int maximumThread,int queueTread){
        this.coreThreadNum=coreThreadNum;
        this.maximumThread=maximumThread;
        this.queueTread=queueTread;
        for (int i = 0; i < coreThreadNum; i++) {//直接启动不用数组存储
            WorkThread work=new WorkThread(threadList,lock,isEmpty);
            new Thread(work).start();//若数组为空就空转等待添加线程
            workList.add(work);
        }
    }

    public void add(Runnable runnable,int i){
        lock.lock();
        try {
            if (threadList.size() < queueTread) {
                threadList.add(runnable);
                System.out.print("第" + i + "个任务存入队列");
                isEmpty.signal();
            } else if (workList.size() < maximumThread) {
                System.out.println("第" + i + "个任务存入启动临时线程中");
                WorkThread workThread = new WorkThread(threadList, lock, isEmpty);
                new Thread(workThread).start();
                workList.add(workThread);
            } else {
                System.out.println("拒绝任务...");
            }
        }finally {
            lock.unlock();
        }
    }
}

这里还有一个拒绝策略,这里我是最简单的当存放的任务数超过了最大处理任务数加队列最多存放的任务数时,就拒绝存放,并且输出反馈。这里还有一个很重要的就是先开启线程,如果没有任务处理就用lock锁给它锁住,直至有任务存放。

接下来就是线程工厂用来处理队列存放的任务和启用核心线程:

public class WorkThread implements Runnable{
    private List<Runnable> threadList;//需要处理的线程
    private Lock lock;
    private Condition isEmpty;

    public WorkThread(List<Runnable> threadList,Lock lock,Condition isEmpty){
        this.threadList=threadList;
        this.lock=lock;
        this.isEmpty=isEmpty;
    }

    @Override
    public void run() {
        Runnable runnable=null;
        while (true){
            lock.lock();
            try {
                while (threadList.isEmpty()) {//是否为空,空的话就等待
                    try {
                        System.out.println(Thread.currentThread().getName() + ":线程等待中...");
                        isEmpty.await();//等待
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                //不为空就进行如下操作
                runnable = threadList.remove(0);
                //获取第一个线程并删除
            }finally {
                lock.unlock();
            }
            runnable.run();
        }
    }
}

这就是一个简易的线程池了。当然线程池还有时间单位和时间长度来限制临时线程的存活时间。实验结果如下:

public class TextWork implements Runnable{
    int t;
    public TextWork(int t){
        this.t=t;
    }
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName() + ":执行任务" + t);
        }
    }
    public static void main(String[] args) {
        ThreadPool threadPool=new ThreadPool(5,10,20);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        for (int i = 0; i < 30; i++) {
            threadPool.add(new TextWork(i),i);
        }
    }
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐