并发编程-Java线程池

17 篇文章 1 订阅
15 篇文章 0 订阅

并发编程-Java线程池

一、简述

线程频繁的创建和销毁造成资源的浪费,如果是在并发情况下,这种频繁的操作会对性能影响非常大。
为了避免线程的频繁创建与销毁,可以创建一定数量的线程集合,在需要使用时,从集合里获取线程;使用完后再将线程放回集合中,实现线程的重复利用。而这个集合就是要说的线程池。

线程池可以提高响应速度(减少创建线程的时间)、降低资源消耗、便于进行线程管理

二、常见的线程池

  • newCachedThreadPool
  • newFixedThreadPool
  • newScheduledThreadPool
  • newSingleThreadExcutor

2.1、线程类

为了使下面的代码更好理解,将任务代码单独写成一个类

public class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println("线程"+Thread.currentThread().getName()+"正在执行");
        try {
            //模拟线程执行
            Thread.sleep(2000);
            Random r = new Random();
            if(1 == r.nextInt(2)){
                System.out.println("任务中断");
                Thread.currentThread().stop();
                throw new Exception("任务中断");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("线程"+Thread.currentThread().getName()+"执行完成");

    }
}

2.2、newCachedThreadPool

  • 创建一个可缓存扩展的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • 工作线程的创建数量最大值为Integer.MAX_VALUE。
  • 如果长时间没有往线程池中提交任务,即如果工作线程持续空闲了指定的时间(默认为1分钟),则该工作线程将自动终止,终止后,如果又提交了新的任务,则线程池重新创建一个工作线程。
  • 一定要注意控制任务的数量,否则,由于大量线程同时运行,很快就会造成系统瘫痪。
 public static void main(String[] args) {
        //创建一个可缓存扩展的线程池
        ExecutorService cachethreadPool = Executors.newCachedThreadPool();
        try {
            for (int i = 0; i < 20; i++) {
                MyThread myThread = new MyThread();
                //提交任务
                cachethreadPool.execute(new Thread(myThread));
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭线程池
            cachethreadPool.shutdown();
        }

    }

2.3、newFixedThreadPool

  • 创建一个指定工作线程数量的线程池,每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池指定的最大值,则将提交的任务存入到等待池队列中。
  • 提高程序效率和节省创建线程时所耗的开销。
  • 在线程池空闲时,即线程池中没有可运行的任务、或者可运行的任务远远小于线程池的已有工作线程的数量时,它不会释放已创建的工作线程,这会导致占用一定的系统资源。
public static void main(String[] args) {
        //创建一个线程数量为5的线程池
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
        try {
            for (int i = 0; i < 20; i++) {
                MyThread myThread = new MyThread();
                //提交20个任务
                fixedThreadPool.execute(new Thread(myThread));
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭线程池
            fixedThreadPool.shutdown();
        }
    }

2.4、newScheduledThreadPool

  • 创建一个指定工作线程数量的线程池,而且支持定时的以及周期性的任务执行。
public static void main(String[] args) {
        //创建一个可定时的线程并且数量为5的线程池
        ScheduledExecutorService scheduledThreadPool = null;
        scheduledThreadPool = Executors.newScheduledThreadPool(5);
        try {
            for (int i = 0; i < 20; i++) {
                MyThread myThread = new MyThread();
                //提交任务,并延迟3秒执行
                scheduledThreadPool.schedule(new Thread(myThread),3, TimeUnit.SECONDS);
                //提交任务,第一次延迟3秒执行,结束后间隔2秒执行一次
                //scheduledThreadPool.scheduleAtFixedRate(new Thread(myThread),3,2,TimeUnit.SECONDS);
                //提交任务,第一次延迟3秒执行,执行后间隔2秒执行一次
                //scheduledThreadPool.scheduleWithFixedDelay(new Thread(myThread),3,2,TimeUnit.SECONDS);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭线程池(执行周期性任务时不能关闭线程池)
            //scheduledThreadPool.shutdown();
        }
    }

2.4、newSingleThreadExcutor

  • 创建一个单线程的Executor,即只创建一个工作线程来执行任务,它只会用唯一的工作线程来执行任务,以保证所有任务按照指定顺序(FIFO,LIFO)执行。
  • 如果这个线程任务异常结束,会有另一个取代,保证任务执行。
  • 单个工作线程最大的特点就是可保证顺序地执行各个任务,并且在任意给定的时间内不会有多个线程同时活动。
public static void main(String[] args) {
        //创建一个可定时的线程并且数量为5的线程池
        ExecutorService singleThreadPool = null;
        singleThreadPool = Executors.newSingleThreadScheduledExecutor();
        try {
            for (int i = 0; i < 20; i++) {
                MyThread myThread = new MyThread();
                //提交任务
                singleThreadPool.execute(new Thread(myThread));
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭线程池
            singleThreadPool.shutdown();
        }
    }

三、自定义线程池

3.1、线程池的实现

通过看源码,可以发现线程池都是通过调用ThreadPoolExecutor方法进行实现的

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

3.2、线程池的7大参数

从实现方法中可以看到有七个参数来设计线程池

  • corePoolSize: 核心线程数量,核心线程会一直存在,除非allowCoreThreadTimeOut设置为true。
  • maximumPoolSize: 线程池允许最大线程数量。
  • keepAliveTime: 已创建线程数量超过corePoolSize时,空闲线程的最大存活超时时间。
  • unit: 超时时间单位。
  • workQueue: 工作等候队列,保存未执行的Runnable任务。
  • threadFactory: 创建线程池中工作线程的工厂。
  • handler: 当线程已满,工作等候队列也满了的时候,将会调用这个方法来实现各种拒绝策略。

3.3、自定义一个线程池

可以通过自定义线程池的参数来定制化线程池

public static void main(String[] args) {
        ThreadFactory myThreadFactory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                return null;
            }
        };
        RejectedExecutionHandler myHandle = new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                //拒绝策略
            }
        };
        ExecutorService myThreadPool = new ThreadPoolExecutor(2,5,3, 
                                                              TimeUnit.SECONDS,
                                                              new LinkedBlockingQueue<>(6),
                                                              myThreadFactory,myHandle);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值