Java并发程序设计(五)JDK并发包之线程复用:线程池

线程复用:线程池

一、为什么需要线程池

为了避免系统频繁地创建和销毁线程,使用线程池让线程进行复用。(即创建线程变成了从线程池中获取空闲线程,销毁线程变成了把线程放回线程池中。)

二、JDK对线程池的支持:Executor框架

一)Excutor框架简介

 

public static ExecutorService newFixedThreadPool(int Threads) //返回一个固定线程数量的线程池,当新任务提交时无空闲线程,则任务进入等待队列,等待空闲线程。

public static ExecutorService newSingleThreadExecutor() //返回一个只有一个线程的线程池,多余的任务被提交到线程池,会进入等待队列,按先入先出顺序执行。

public static ExecutorService newCahedThreadPool() //返回一个可根据实际情况调整线程数量的线程池

public static ScheduledExecutorService newSingleThreadScheduledExecutor() //线程池中的线程可根据时间执行任务。

public static ScheduledExecutorService newScheduledThreadPool()
public class SESDemo {

    public static void main(String[] args){
        ScheduledExecutorService p = Executors.newScheduledThreadPool(10);
        p.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try{
                    Thread.sleep(1000);
                    System.out.println(System.currentTimeMillis()/1000+" and name is "+
                            Thread.currentThread().getName());
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        },0,2, TimeUnit.SECONDS);
    }
}
/*1504236959 and name is pool-1-thread-1
1504236961 and name is pool-1-thread-1
1504236963 and name is pool-1-thread-2
1504236965 and name is pool-1-thread-1
1504236967 and name is pool-1-thread-3
1504236969 and name is pool-1-thread-2
.......
1504237017 and name is pool-1-thread-7
1504237019 and name is pool-1-thread-7
1504237021 and name is pool-1-thread-7
1504237023 and name is pool-1-thread-7
1504237025 and name is pool-1-thread-7
*/

注意:任务本身不能抛出异常,不然后续所有执行都会被中断。

二)框架内部实现:

以上方法具体实现都使用了ThreadPoolExecutor,它们都封装了ThreadPoolExecutor

其中workQueue指被提交但未被执行的任务队列。

 

 

 拒绝策略:线程池中的线程已经用完,队列也已经排满。

JDK内置的四种拒绝策略:

AbortPolicy:直接抛出异常,阻止系统正常执行。

CallerRunsPolicy:直接在任务提交的线程内执行线程。

DiscardOledestPolicy:丢弃最老的一个任务,并再次提交当前任务。

DiscardPolicy:丢弃无法处理的当前任务,不做其他处理。

以上策略都实现了RejectedExecutionHandler接口,如果以上策略无法满足我们的需求,我们可以扩展该接口。

public class RejectThreadPoolDemo {
    public static class MyTask implements Runnable{
        @Override
        public void run() {
            System.out.println(System.currentTimeMillis()+" :Thread ID:"+
            Thread.currentThread().getId());

            try{
                    Thread.sleep(100);
                }catch (Exception e){
                    e.printStackTrace();
                }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyTask myTask=new MyTask();
        ThreadPoolExecutor es = new ThreadPoolExecutor(5, 5, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(10)
                , Executors.defaultThreadFactory(),
                new RejectedExecutionHandler() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        System.out.println(r.toString() + "is discard");
                    }
                });

        for (int i=0;i<Integer.MAX_VALUE;i++){
            es.submit(myTask);
            Thread.sleep(10);
        }
    }
}

三)自定义线程创建

线程池中线程的来源:ThreadFactory接口。override该接口中的

public Thread newThread(Runnable r);

方法即可。

四)扩展线程池

ThreadPoolExecutor是个可以扩展的线程池接口,它提供了beforeExecutor(),afterExecutor()和terminated三个接口对线程池进行控制。

public class ExtThreadPool {

    public static class Mytask implements Runnable{
        private String name;

        public Mytask(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            System.out.println("正在执行:线程ID"+Thread.currentThread().getId()+
            "任务名:"+name);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService es=new ThreadPoolExecutor(5,5,0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>()){

            @Override
            protected void beforeExecute(Thread t, Runnable r) {
                System.out.println("准备执行:"+((Mytask)r).name);
            }

            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                System.out.println("执行完毕:"+((Mytask)r).name);
            }

            @Override
            protected void terminated() {
                System.out.println("线程池退出");
            }
        };

        for (int i=0;i<5;i++){
            Mytask mytask=new Mytask("task"+i);
            es.execute(mytask);
            Thread.sleep(10);
        }

        es.shutdown(); //所有任务执行完毕后,关闭线程池。
    }
}

 

五)线程池中寻找异常堆栈

解决多线程中幽灵般的异常:

方法一:放弃submit()改用execute()

方法二:extends ThreadPoolExecutor

 

六)分而治之,Fork/Join框架

分阶段对大量数据进行处理,然后对结果进行整合。

 

 互助精神:

重要接口:

public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task)

ForkJoinTask两个重要子类:

 

转载于:https://www.cnblogs.com/Shadowplay/p/7462763.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值