java线程池原理,常见线程池

java线程池原理

Executors类提供了FixedThreadPool、CachedThreadPool等线程池对象,都是基于ThreadPoolExecutor产生的。

Executor接口定义了execute(),子接口ExecutorService又定义了submit(),抽象类AbstractExecutorService继承了该子接口,调用execute()实现了submit(),ThreadPoolExecutor继承AbstractExecutorService接口,实现了execute()。

ThreadPoolExecutor主要持有一个HashSet用于存储worker,持有一个阻塞队列用于存储待执行的任务(Runnable/Callable)。如果HashSet未达到指定大小,接到任务时立即创建worker,否则将任务存入阻塞队列。创建worker时启动一个线程,构造worker时传入的第一个Runnale开始执行,执行完后通过getTask()从阻塞队列中取出任务继续执行。

public class ThreadPoolExecutor extends AbstractExecutorService {
    //持有阻塞队列和HashSet,分别存放排队的任务和已有的worker。
    private final BlockingQueue<Runnable> workQueue;
    private final HashSet<Worker> workers = new HashSet<Worker>();
...
    private boolean addWorker(Runnable firstTask, boolean core) {
        Worker w = new Worker(firstTask);
        Thread t = w.thread;
        workers.add(w);
        //启动worker持有的线程。
        t.start();
    }
...
    final void runWorker(Worker w) {
        //让worker开始执行任务
        Runnable task = w.firstTask;
        //第一次执行firstTask,之后循环从队列中取任务执行
        while (task != null || (task = getTask()) != null) {
            task.run();
        }
    }
...
    private Runnable getTask() {
        //此处决定了是一直阻塞还是超时结束
        Runnable r = timed ?
        workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
        workQueue.take();
    }
...
    private final class Worker implements Runnable{
        //注意worker本身也是一个Runnable
        Worker(Runnable firstTask) {
            //创建worker时就创建了新线程,同时持有了第一个任务,但此时线程没有执行!
            this.firstTask = firstTask;
            //注意该线程传入的是worker自身,start()后运行的是下面的run(),
            this.thread = getThreadFactory().newThread(this);
        }
        public void run() {
            //在worker的线程中执行外部类的runWorker(Worker w)方法
            runWorker(this);
        }
    }
}

实现细节:worker本身接收一个Runnable任务,同时持有一个线程(该线程包含的Runnable就是worker自己!),线程池新建worker后调用worker.thread.start()开始子线程,执行worker的run(),在子线程中调用外部类的runWorker()方法(worker作为内部类的对象可以调用外部类的方法),从外部的HashSet中读取任务,从而实现在子线程中运行外部类队列中任务的目的!!同时在HashSet中保存worker的引用,便于对子线程进行管理。

 

FixedThreadPool、CachedThreadPool的区别主要在于HashSet的大小限制和getTask()时表现不同,FixedThreadPool的HashSet大小由参数决定,同时运行的线程数有限,同时getTask()时使用的是阻塞队列的take()方法,无任务时一致阻塞,线程不会结束。CachedThreadPool的HashSet大小为Integer.MAX_VALUE,可以无限增加,getTask()时使用的是poll(),阻塞队列的该方法在延时后返回null,所以该线程池的线程一段时间不用后会自动结束。

public class ThreadPoolExecutor{
//ThreadPoolExecutor的通用线程策略是:
//1、线程数小于核心线程数时,尝试创建线程
//2、达到核心线程数时,尝试放入任务队列
//3、放入失败时开始第二次新建线程阶段(CachedThreadPool就是利用了这一点),大于最大线程数时就报错。
...
    //CachedThreadPool与FixedThreadPool在无任务时线程是否结束上的区别就在于此
    private Runnable getTask(){
    ...
        Runnable r = timed ?
        workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
        workQueue.take();
    ...
    }
...
}

//线程数上限Integer.MAX_VALUE,60秒无任务就结束
public static ExecutorService newCachedThreadPool() {
    //默认60秒无任务就结束
    //核心线程数为0,即一有任务立即进入第二阶段尝试放入任务队列
    //而SynchronousQueue性质是若有线程等待则放入操作会成功,无任务等待时放入操作失败,线程池自动进入第二次新建线程阶段。
    //从而实现了复用空闲线程,无空闲线程则自动新建的功能。
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
//固定大小线程池,无任务时一直等待,不结束
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

另外两个常见的线程池SingleThreadExecutor、ScheduledThreadPool

//单线程池SingleThreadExecutor就是newFixedThreadPool(1)
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>())
        );
}

//延时调度线程池,对于池中的每个线程,runnable任务可以设置延时执行,且可以设为隔段时间重复执行
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
    ThreadPoolExecutor(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
            new DelayedWorkQueue());
}

        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(2);
        //延时0秒,每隔3秒重复执行一次
        //scheduleAtFixedRate   下次任务开始-本次任务开始=3秒
        //scheduleWithFixedRate 下次任务开始-本次任务结束=3秒
        threadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("3");
            }
        },0,3, TimeUnit.SECONDS);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值