天天看点

JAVA 线程池原理---简洁代码实现

抽空自学了一下java线程池工作原理,简单记录一下。

说明:博主由于博客写的比较少,格式不熟练。下文贴的代码格式可能不是很好。

1.线程池的接口实现如下图所示(图片引用别处)

JAVA 线程池原理---简洁代码实现

2.线程池的作用

线程池的工作主要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果任务数量超过了最大线程数量,需要进入队列排队等候,等其他线程执行完毕,再从队列中取出任务来执行。

3.主要特点

a.线程复用

b.控制最大并发数量

c.管理线程

4.使用线程池的好处

a.降低了资源消耗。通过复用机制降低了线程创建和销毁的消耗。

b.提高了响应速度。当任务到达时,任务不需要等候就能立即执行。

c.提高了线程的可管理性。线程是稀缺的,如果无限制创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配,调优和监控。

5.自己实现线程池

5.1 思考?实现一个线程池需要什么?

  1. 存放任务的队列或者仓库
  2. 工作线程,不停的执行任务
  3. 线程容器,存放工作线程,便于管理
  4. 阻塞的提交任务方法
  5. 不阻塞的提交任务方法
  6. 线程池初始化
  7. 线程池销毁方法

5.2 源码实现

public class MyThreadPool{

	//存放任务的队列或者仓库
	private BlockingQueue<Runnable> blockingQueue;
	
	//线程容器,存放工作线程,便于管理
	private List<Thread> workers;
	//工作线程 需要包装一下
	public static class Worker extends Thread{
	
	 private MyThreadPool pool;
	  public Worker(MyThreadPool pool){
	            this.pool = pool ;
	        }

 	    @Override
        public void run() {
		//线程池不是停止状态 或者任务队列有队列时需要工作
            while (this.pool.isWorking || this.pool.blockingQueue.size()>0){

                Runnable task = null;

                    try {
                        if(this.pool.isWorking){
                            task = this.pool.blockingQueue.take();
                        }else
                            task = this.pool.blockingQueue.poll(); //非堵塞

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                if(task !=null){
                    task.run();
                }

            }

        }
 
}

	//线程池的初始化
	public MyThreadPool(int poolsize,int queueSize)  {

        if(poolsize<0 || queueSize<0){
            throw new IllegalArgumentException("非法参数");
        }
        this.blockingQueue =  new LinkedBlockingQueue<>();

        this.workers = Collections.synchronizedList(new ArrayList<Thread>());

        for(int i=0;i<poolsize;i++){
            Worker worker = new Worker(this);  // 实例化线程
            worker.start(); //开始执行任务
            this.workers.add(worker); //加入任务线程
        }
    }

	//提交任务 非阻塞

   public boolean submit(Runnable task){

        if(isWorking){
            if(this.blockingQueue.offer(task)){
                return true;
            }
        }

        return false;
    }
}

	// 提交任务 阻塞
	public void execute(Runnable task){
	        try {
	            if(isWorking){
	                this.blockingQueue.put(task);
	            }
	
	        } catch (InterruptedException e) {
	            e.printStackTrace();
	        }
    }


	//线程池的关闭条件
	 //任务无法加入
    //处理完所有任务
    //关闭时,不需要阻塞,没有任务需要处理
    //关闭时,阻塞得任务需要中断
    private volatile boolean isWorking = true;

    public void shutDown(){
        this.isWorking = false ;
        for(Thread th : workers){
            if(th.getState().equals(Thread.State.BLOCKED) || th.getState().equals(Thread.State.WAITING) ||
            th.getState().equals(Thread.State.TIMED_WAITING)){
                th.interrupt();
            }
        }


    }
           

5.3测试

public static void main(String args[]) throws InterruptedException {
        MyThreadPool myThreadPool = new MyThreadPool(3,6);

        for (int i=0; i<50; i++){
            myThreadPool.submit(new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread()+"任务正在执行中。。。");
                    try {
                        Thread.sleep(2500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        /*Thread.sleep(15000);
        myThreadPool.shutDown();*/
    }
           

6.总结

本篇文章实现了一个简单的线程池,但是实际中的线程池工作原理已经和本文很类似了。结合线程池源代码进行阅读。应该可以很快的理解线程池源代码了。