Java实现简单线程池

Java实现简单线程池

简介

在这篇博文中,我会实现一个简单的线程池。

线程池的基本要素有:

1.任务队列,负责接收要调度的任务。

2.线程容器,负责创建多个线程,并依据一定的策略调度任务。

3.生命周期方法,线程池中的线程会不断地等待新任务的到来。如果不提供方法明确取消线程的执行,任务执行完后程序不会终止。注意我们如何实现取消线程。

小知识:Java中线程分为普通线程和Deamon线程两种,Java进程在普通线程全部执行完成之前,不会终止。

4.线程池的实现使用了生产者消费者模式。

另外,为了符合大家的习惯,接口设计会参照jdk中相关接口。

Java代码

我会把线程池框架代码和客户端调用代码分离,请大家注意这个细节。

框架代码

首先是外部接口的定义

public interface ExecutorService {
    void execute(Runnable task);
    void shutDown();
}

任务队列

package org.lin.thread.executor.framework;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 任务队列,生产者消费者模式中的Channel角色
 * @author linjingfu
 *
 */
public class TaskQueue {
    private Queue<Runnable> taskList = new LinkedList<>(); //任务队列
    private boolean terminated = false;  //我们使用synchronized保护可见性

    //构造方法包可见性,不希望框架外代码实例化该类
    TaskQueue() {}

    public synchronized Runnable take() throws InterruptedException {
        if (terminated && taskList.isEmpty()) {
            return null;
        }
        while (taskList.isEmpty()) {
            wait();
        }
        Runnable task = taskList.poll();
        notifyAll();
        return task;
    }

    public synchronized void put(Runnable task) throws InterruptedException {
        while (taskList.size() == Integer.MAX_VALUE) {
            wait();
        }
        taskList.add(task);
        notifyAll();
    }

    public synchronized void setTerminated(boolean terminated) {
        this.terminated = terminated;
    }

}

工作者线程

package org.lin.thread.executor.framework;

/**
 * 工作线程,消费者
 * @author linjingfu
 *
 */
public class TaskThread extends Thread{
    private TaskQueue queue;

    public TaskThread(int id, TaskQueue queue) {
        this.queue = queue;
        setName("pool-thread-No." + id);
    }

    @Override
    public void run() {
        try {
            while (true) {
                Runnable task = queue.take();
                if (task == null) {
                    //取不到,说明已经被shutDown,并且任务执行完成
                    break;
                }
                task.run();
            }
        } catch (InterruptedException e) {
        }
    }
}

线程数量固定的线程池

package org.lin.thread.executor.framework;

/**
 * 线程池对象,任务生产者
 * @author linjingfu
 *
 */
public class FixedThreadPool implements ExecutorService{

    private Thread[] threads; //保留线程引用,以中断线程执行
    private TaskQueue queue = new TaskQueue();

    FixedThreadPool(int threadNum) {
        threads = new Thread[threadNum];
        for (int i = 0; i < threadNum; i++) {
            threads[i] = new TaskThread(i + 1, queue);
            threads[i].start();
        }
    }

    @Override
    public void execute(Runnable task) {
        if (task == null) {
            throw new IllegalArgumentException("task不能为null!");
        }
        try {
            queue.put(task);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void shutDown() {
            queue.setTerminated(true);
    }

}

简单工厂提供获取线程池的接口

package org.lin.thread.executor.framework;

/**
 * 简单工厂,生成线程池
 * @author linjingfu
 *
 */
public class Executors {
    public static ExecutorService newFixedThreadPool(int threadNum) {
        return new FixedThreadPool(threadNum);
    }
}

客户端调用代码

package org.lin.thread.executor;

import java.util.concurrent.atomic.AtomicInteger;

import org.lin.thread.executor.framework.ExecutorService;
import org.lin.thread.executor.framework.Executors;

public class Client {

    private static AtomicInteger taskId = new AtomicInteger(0);

    public static void main(String[] args) {
        //创建自定义线程池
        ExecutorService service = Executors.newFixedThreadPool(5);
        //使用线程池执行10个任务
        for (int i = 0; i < 10; i++) {
            service.execute(() -> {
                for (int j = 0; j < 100000000; j++) {
                    //模拟耗时任务
                }
                System.out.println("在线程  " + Thread.currentThread().getName() + " 中任务" + taskId.incrementAndGet() + "执行完成!");
            });
        }
        //在任务执行完后,终止工作线程
        service.shutDown();
    }
}

运行结果

这里写图片描述

总结

上面的代码,都是我看完《图解多线程设计模式》一书的Worker Thread模式后独自编写的,获益良多。

从上面代码中,可以学习多线程编程的几点内容:

1.在类中封装互斥策略,如TaskQueue类使用this锁来进行互斥加锁的操作,其他的类,如FixedThreadPool和TaskThread类在调用TaskQueue的同步方法时,不需要去考虑线程安全问题。

2.使用wait()和notify()实现线程协作。

3.这里我们通过检测标志变量terminated,从而取消工作者线程,同样我们将取消策略封装在了TaskQueue中。

4.这一点不属于多线程编程的内容,但可以看到框架中的一些类,我们将构造函数设为包级可见,只对外提供了ExecutorService接口,以及工厂类Executors,好处是可以防止框架内部的类被误用。

猜你喜欢

转载自blog.csdn.net/qq_21508059/article/details/78944058
今日推荐