Java--线程池

Java中提供了一系列和锁相关的工具:synchronized、ReentrantLock、AtomicXXX类,它们都能帮助解决我们进行多线程操作时并发问题,之前我们也提到了内核线程模型,Hotspot虚拟机线程的创建都是通过内核线程提供的轻量级进程API创建的,反复的创建线程会不断的由OS线程调度,这也会消耗大量CPU性能
争对创建线程,除了使用Thread之外,Java还提供了线程池类,它们最终都实现的Executor接口,JDK1.7中的继承实现关系如下:
一、使用线程池与Thread对比

使用Thread创建10000个线程,并运行,记录时间:

public class ThreadPoolTest {

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        List<Thread> threads = new ArrayList<>(10000);

        for (int i = 0; i < 10000; i++) {
            Thread thread = new Thread();
            threads.add(thread);
            thread.start();
        }

        for(Thread t:threads){
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("ms:"+(System.currentTimeMillis() - startTime));
    }

}

结果:
ms:1761

使用线程池:

public class ThreadPoolTest2 {

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        int size = 10000;

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        final CountDownLatch countDownLatch = new CountDownLatch(size);

        for (int i = 0; i < size; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    countDownLatch.countDown();
                }
            });
        }

        try {
            countDownLatch.await();//等待10000计数结束
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
        System.out.println("ms:" + (System.currentTimeMillis() - startTime));
    }

}

结果:
ms:69

两者相差的时间为100倍以上,这边使用的线程池回头再来看,由这个例子可以看出,线程的创建到运行过程,会花费大量的cpu时间,争对需要大量并发的操作,使用线程池可以大大提高程序性能

二、ThreadPoolExecutor
1.ThreadPoolExecutor执行任务图解

Executors是个帮助类,内部实际使用的是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.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

ThreadPoolExecutor大致的执行场景如下:

execute方法执行流程
2.ThreadPoolExecutor参数

再来看构造函数中各个参数的含义:

  • corePoolSize:核心线程最大数,当有新任务时,如果小于该值,那么会直接创建线程或使用空闲的核心线程执行任务

  • maximumPoolSize:最大线程数,需大于核心线程数,非核心线程最大数 = 最大线程数 - 核心线程最大数,当核心线程全部创建并都在执行任务,那么新任务使用非核心线程执行,同样使用核心线程创建机制:创建线程或使用空闲的线程,非核心线程可以指定死亡时间,相当于临时工

  • keepAliveTime:非核心线程的保持存活时间,当一个非核心线程持续keepAliveTime时间都处于空闲状态,那么使它消亡

  • unit:保持存活时间的时间单位

  • workQueue:任务队列,当线程总数到达最大,并且所有线程都有任务在执行,那么新任务可以进入该队列,等待有线程空闲时执行队列中的任务。通过Executors创建的任务队列,都没有最大值,所以当遇到服务器并发量大的情况,容易OOM,安卓开发中不需要考虑这个问题

  • threadFactory:创建线程工厂,一般使用默认的即可

  • handler:拒绝策略,当触发拒绝时,执行该对象策略策略

3.任务队列

任务队列实现BlockingQueue接口,JDK提供了以下4种:

  • ArrayBlockingQueue: 是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
  • LinkedBlockingQueue: 一个基于链表结构的阻塞队列,此队列按FIFO(先进先出)排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
  • SynchronousQueue: 一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
  • PriorityBlockingQueue: 一个具有优先级的无限阻塞队列
4.拒绝策略
  • DiscardPolicy:丢弃当前将要加入队列的任务本身。
  • DiscardOldestPolicy:丢弃任务队列中最旧任务。(丢弃最旧任务也不是简单的丢弃最旧的任务,而是有一些额外的处理)
  • AbortPolicy:抛出异常的方式。
  • CallerRunsPolicy:不进入线程池执行,由调用者线程执行。
三、Executors

后台一般不允许使用Executors,但我们安卓开发是可以使用的,接下来来使用Executors三种线程池,有了上面ThreadPoolExecutor的了解,理解起来很简单

public class ThreadPoolTest3 {

    public static void main(String[] args) {
        ExecutorService executorService1 = Executors.newCachedThreadPool();
        ExecutorService executorService2 = Executors.newFixedThreadPool(10);
        ExecutorService executorService3 = Executors.newSingleThreadExecutor();
        for (int i = 1; i <= 100; i++) {
            executorService1.execute(new TestRunnable(i));
//            executorService2.execute(new TestRunnable(i));
//            executorService3.execute(new TestRunnable(i));
        }
    }

    static class TestRunnable implements Runnable {
        int i = 0;

        public TestRunnable(int i) {
            this.i = i;
        }


        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + ":" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
1.newCachedThreadPool

newCachedThreadPool方法如下:

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

它和直接创建线程类似,可以创建无限的线程

2.newFixedThreadPool

newFixedThreadPool方法如下:

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

它拥有指定大小的核心线程数,并且只有核心线程,以及一个无限大小的任务队列

3.newSingleThreadExecutor

newSingleThreadExecutor方法如下:

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

它仅有一个核心线程,以及一个无限大小的任务队列,所以相当于单线程执行任务队列中的任务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值