回顾线程池技术------学习笔记

回顾线程池技术------学习笔记

一、出现的背景

Thread功能繁多,而且对线程数量没有管控,对于线程的开辟和销毁要消耗大量的资源。每次new一个Thread都要重新开辟内存

二、优点或者功能

1、降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

2、提高响应速度:当任务到达时,可以不需要等待线程创建就能立即执行。

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

三、了解有关的几个类

继承与实现

首先是Executor:

public interface Executor {
    void execute(Runnable command);
}

是一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command),该方法接收一个Runable实例,它用来执行一个任务,任务即一个实现了Runnable接口的类

ExecutorService:

public interface ExecutorService extends Executor{

在这里插入图片描述
}

是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,返回 Future 对象,以及可跟踪一个或多个异步任务执行状况返回Future的方法;可以调用ExecutorService的shutdown()方法来平滑地关闭 ExecutorService,调用该方法后,将导致ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后将会关闭ExecutorService。因此我们一般用该接口来实现和管理多线程。

Executors类: 主要用于提供线程池相关的操作

使用 Executors 创建四种类型的线程池

  1. FixedThreadPool
 public static ExecutorService newFixedThreadPool(int nThreads){
    return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}

它是一种固定大小的线程池;
corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads;
keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉;但这里keepAliveTime无效;
阻塞队列采用了LinkedBlockingQueue,它是一个无界队列;
由于阻塞队列是一个无界队列,因此永远不可能拒绝任务;
由于采用了无界队列,实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。
2. CachedThreadPool

public static ExecutorService newCachedThreadPool(){
    return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>());
}
  1. SingleThreadExecutor
 public static ExecutorService newSingleThreadExecutor(){
    return new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}

它只会创建一条工作线程处理任务;
采用的阻塞队列为LinkedBlockingQueue;
4. ScheduledThreadPool
它用来处理延时任务或定时任务。

Executors为我们提供了这四种线程池。我们可以使用这么这几个线程解决日常问题。但在使用Executors创建线程池可能会导致OOM(OutOfMemory ,内存溢出)。

四、以自定义创建线程池

除了上述的四种Executors提供的四种线程池外。我们当然可以自定义创建线程池来更加效率的满足我们的需求。
直接调用ThreadPoolExecutor的构造函数(还有很多个不同参的构造函数)来自己创建线程池,上面工具类的四个线程池也是直接或间接如此创建的。源码:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), handler);
}

corePoolSize :线程池中核心线程数的最大值
maximumPoolSize :线程池中能拥有最多线程数
keepAliveTime :表示空闲线程的存活时间。
TimeUnit unit :表示keepAliveTime的单位。
threadFactory :指定创建线程的工厂
handler :拒绝策略

详细见一位前辈的博客非常详细,参数的关系和差异讲的也很生动ThreadPoolExecutor 参数详解

五、任务的提交过程

1.submit方法

submit 的实现方法位于抽象类 AbstractExecutorService 中,而此时 execute 方法还未实现(而是在 AbstractExecutorService 的继承类 ThreadPoolExecutor 中实现)。submit 有三种重载方法,这里我选取了两个常用的进行分析,可以看出无论哪个submit 方法都最终调用了 execute 方法

2.execute方法

由于execute方法中多次调用 addWorker ,我们这里就简要介绍一下它,这个方法的主要作用就是创建一个线程来执行Runnnable对象。

3.addWorker方法

六、线程池代码实例:

import java.util.concurrent.*;

public class ThreadPool {
    /**
     * 创建线程池
     * @return 返回线程池管理对象实例
     */
    public ThreadPoolExecutor createThreadPool(){

        return new ThreadPoolExecutor(10, 15,
                20L, TimeUnit.SECONDS,
                new ArrayBlockingQueue(10),
                //拒绝策略:抛弃最旧的任务(最先提交而没有得到执行的任务)
                new ThreadPoolExecutor.DiscardOldestPolicy());
    }

}
import java.util.Random;

public class Task implements Runnable{
    private int id;
    public  Task(int id){
        this.id = id;
    }
    @Override
    public void run() {
        int t =new Random().nextInt(10);
 /*       for (int i = 0; i < t; i++) {
            System.out.println(Thread.currentThread().getName() + "run : " + i);
        }*/
        try {
            Thread.sleep(t*500);
        }catch (Exception e){
            e.printStackTrace();
        }

    }

}
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
public class ThreadPoolTest {
    @Test
    public void threadPoolTest(){
        ThreadPool threadPool = new ThreadPool();
        ThreadPoolExecutor threadPoolExecutor =threadPool.createThreadPool();
        for (int i = 0; i < 20; i++) {
            Task task = new Task(i);
            //0.5s提交一个任务
            try {
                Thread.sleep(500);
            }catch (Exception e){
                e.printStackTrace();
            }
            threadPoolExecutor.execute(task);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值