Java 之 线程池的实现原理与使用

Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或者并发执行任务的程序都可以使用线程池。

1.线程池优点:

1)降低资源消耗:通过重复利用已创建的线程降低线程创建于销毁带来的损耗
2)提高相应速度:当任务到达时,无需等待线程创建就可以立即执行
3)提高线程的可管理性:使用线程池可以统一进行线程分配、调度与监控

2.线程池的实现原理
线程池的主要处理流程如下:

1)判断核心线程池是否已满,如果未满,创建一个新的线程来执行任务。如果已满,判断是否有空闲线程,有的话将任务分配给空闲线程,否则,执行步骤2。(corePoolSize)(创建线程需要获得全局锁)

2)判断工作队列(阻塞队列BlockingQueue)是否已满。如果工作队列未满,将任务存储在工作队列中等待空闲线程调度。如果工作队列已满,执行步骤3。(BlockingQueue)

3)判断当前线程池的线程数量是否已达到最大值,如果没有达到最大值,则创建新的线程来执行任务。(创建线程需要获取全局锁)否则执行步骤4。(MaxPoolSzie)

4)调用饱和策略来处理此任务。(RejectPolicy)

3.线程池的使用

  1. 手工创建一个线程池

通过new一个ThreadPoolExcetor就可以实现自定义线程池
例:

public threadPoolExcetor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable>workQueue,
RejectedExcecutionHandler handler)

1)coolPoolSize(核心线程池大小):当提交一个任务到线程池时,只要核心线程池为达到corePoolSize,创建新线程来执行任务。
preStartAllCoreThreads( ):线程池会提前创建并启动所有核心线程。

2)BlockingQueueworkQueue(任务队列):保存等待执行任务的阻塞队列。

  • ArrayBlockingQueue:基于数组的有界阻塞队列,按照FIFO原则对元素进行排序。
  • LinkedBlockingQueue:基于链表的无界阻塞队列,按照FIFO排列元素。吞吐量要高于ArrayBlockingQueue.
    (内置线程池newFixedThreadPool-固定大小线程池就采用此队列。)
  • synchronousQueue:一个不存储元素的阻塞队列(无界队列)。每个插入操作需要等待另一个线程移除操作,否则插入操作一直处于阻塞状态。
    吞吐量通常高于LinedBlockingqueue。

内置线程池newCachedThreadPool-缓存线程池就采用此队列。

  • PriorityBlockingQueue:具有优先级的阻塞队列。3)maximumPoolSize(线程池最大数量)

4)keepAliveTime(线程保持活动的时间):线程池的工作线程空闲后保持存活的时间。任务比较多,并且每个任务执行的时间比较短,可以调大此参数来提高线程利用率。

5)RejectedExcecutionHandler(饱和策略)

AbortPolicy:无妨处理新任务抛出异常(JDK默认采用此策略)

CallerRunsPolicy:使用调用者所在线程来处理任务
DisCardOldestPolicy:丢弃队列中最近的一个任务并执行当前任务DisCardPolicy:不处理任务,丢弃任务,也不报异常

4.向线程池提交任务

可以使用俩个方法向线程池提交任务,分别为execute()和submit()方法。

execute()方法用于提交不需要返回值的任务,座椅无法判断任务是否被线程池执行成功。

eg:使用execute()方法:

class MyThreadExecute implements Runnable{
    @Override
    public void run() {
        for (int i = 0;i < 50;i++){
            System.out.println(Thread.currentThread().getName()+" "+i);
        }
    }
}

public class TestExecute {
    public static void main(String[] args) {
       MyThreadExecute myThreadExecute = new MyThreadExecute();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                3,5,2000,TimeUnit.MILLISECONDS,new LinkedBlockingDeque<Runnable>());
        for (int i = 0;i < 5;i++){
            threadPoolExecutor.execute(myThreadExecute);
        }
    }
}

submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过future对象可以判断任务是否执行成功,并且可以通过future的
get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)方法会阻塞当前线程一段时间后立即返回,这时候有可能任务没有完成。

eg:

class CallableThread implements Callable<String>{
    @Override
    public String call() throws Exception {
        for (int i = 0;i < 50 ;i++){
            System.out.println(Thread.currentThread().getName()+","+ i);
        }
        return Thread.currentThread().getName()+"执行完毕";
    }
}

public class TestSubmit {
    public static void main(String[] args) {
        CallableThread callableThread = new CallableThread();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                3,5,2000,
                TimeUnit.MILLISECONDS,new LinkedBlockingDeque<Runnable>());
        for (int i = 0; i < 5;i++){
            Future<String> future = threadPoolExecutor.submit(callableThread);
            try {
                String str = future.get();
                System.out.println(str);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值