【JavaSE】多线程之线程池

1.使用线程池的优点:

I.降低资源的消耗:通过重复利用已创建的线程降低线程创建于销毁带来的损耗。

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

III.提高线程的可管理性:使用线程池可以统一进行线程的分配、调度与监控。

2.线程池执行任务的流程:

当一个Runnable或Callable对象到达线程池时,执行策略如下:

第一步:首先判断核心线程池中的线程是否都在执行任务,如果是,再次查看核心线程池是否已满,如果未满,创建新的线程任务。如果核心线程池有空闲线程,则将任务直接分配给空闲线程执行。否则执行第二步。

第二步:判断工作队列(BlockingQueue)是否已满,如果工作队列没有满,将提交任务存储到工作队列中等待核心池的调度,否则,若工作队列已满,进入步骤3

第三步:判断当前线程池中的线程数是否已到达最大值maxiumSize,若已到达最大值,将任务交给饱和策略处理;否则,继续创建新线程执行此任务。

3.线程池的使用

3.1手工创建线程池

通过创建ThreadPoolExecutor来创建线程池:

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

I.corePoolSize(核心池的大小):当提交任务线程池时,线程池会创建一个新的线程来执行任务,即使线程池中有其他空闲线程也会创建线程,一直到线程数达到核心池的大小为止。调用prestarAllCoreThreads()线程池会提前创建并启动所有核心线程。

II.workQueue(工作队列):用于保存等待执行任务的阻塞队列。可以选择以下几个阻塞队列

a.ArrayBlockingQueue:基于数组结构的有界阻塞队列,此队列按照FIFO原则对队列进行排序

b.LinkedBlockingQueue:基于链表结构的阻塞队列,按照FIFO排序元素,吞吐量高于ArrayBlockingQueue,Executor.newFixedThreadPool()采用此队列

c.SynchronousQueue:一个不存储元素的阻塞队列,无界队列。每个插入元素操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,通常吞吐量高于LinkedBlockingQueue,Executor.newCachedThreadPool()采用此队列。

d.PriorityBlockingQueue:具有优先级的无界阻塞队列。

III.maxiumPoolSize(线程池最大线程数量):线程池允许创建的最大线程数。如果队列已满并且以创建的线程数小于此参数,则线程池会在创建新的线程执行任务,否则,调用饱和策略。采用无界队列,此参数无意义。

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

V.TimeUnit(IV参数的时间单位)

VI.RejectedExecutorHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态。此时采用饱和策略来处理任务,默认采用AbortPolicy,JDK一共内置4个饱和策略。

a.AbortPolicy,表示无法处理新任务抛出异常,JDK默认采用此策略。

b.CallerRunPolicy,等待调用者线程空闲后运行任务

c.DiscardOldestPolicy,丢弃阻塞队列中最近的一个任务,并执行当前任务

d.DiscardPolicy,不处理,直接将新任务丢弃,也不报错。

例:手工创建一个线程池

ThreadPoolExecutor threadPoolExecutor = 
                new ThreadPoolExecutor(3,5,2000,TimeUnit.MICROSECONDS,new LinkedBlockingDeque<Runnable>());

3.2简单使用线程池

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

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

例:使用execute()方法

class MyThread implements Runnable{
    @Override
    public void run() {
        for(int i=0; i<50; i++){
            System.out.println(Thread.currentThread().getName()+"、"+i);
        }
    }
}
public class Test2{
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(3,5,2000,TimeUnit.MICROSECONDS,new LinkedBlockingDeque<Runnable>());
        for(int i=0; i<5; i++){
            threadPoolExecutor.execute(myThread);
        }
        threadPoolExecutor.shutdown();
    }
}

        submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成。一次只执行一个线程(阻塞其他线程),只有当一个线程执行完毕后,才会调用其他线程。

例:使用submit()方法

class MyThread 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 Test2{
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        ThreadPoolExecutor threadPoolExecutor =
                new ThreadPoolExecutor(3,5,2000,TimeUnit.MICROSECONDS,new LinkedBlockingDeque<Runnable>());
        for(int i=0; i<5; i++){
            Future<String> future = threadPoolExecutor.submit(myThread);
            try {
                String str = future.get();
                System.out.println(str);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
        threadPoolExecutor.shutdown();
    }
}

3.3关闭线程池

例:关闭线程池

threadPoolExecutor.shutdown();

4.JDK内置的四大线程池

普通调度池:

I.创建无大小限制的线程池:Executor.newCachedThreadPool(),适用于很多短期任务的小程序,负载较轻的服务器。

II.创建固定大小线程池:Executor.newFixedThreadPool(int nThreads),适用于为了满足资源管理的需求而需要限制当前线程数量的应用场合,适用于负载较中的服务器。

III.单线程池:Executor.newSingleThreadPool(),适用于需要保证顺序的执行各个任务,并且在任意时间点不会有多个线程活动的场景。

定时调度池

Executor.newScheduledThreadPool()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gx1500291

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值