码迷,mamicode.com
首页 > 编程语言 > 详细

Java线程池

时间:2017-12-31 22:26:39      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:available   gui   结构   dex   body   jdk1.5   catch   final   活动   

new Thread的弊端:

1 new Thread(new Runnable() {
2 
3     @Override
4     public void run() {
5         // TODO Auto-generated method stub
6     }
7 }).start();

new Thread的弊端如下:

  a. 每次new Thread新建对象性能差。
  b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
  c. 缺乏更多功能,如定时执行、定期执行、线程中断。
相比new Thread,Java提供的四种线程池的好处在于:
  a. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  b. 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  c. 高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

 

可以通过ThreadPoolExecutor来创建一个线程池:

1     public ThreadPoolExecutor(int corePoolSize,
2                               int maximumPoolSize,
3                               long keepAliveTime,
4                               TimeUnit unit,
5                               BlockingQueue<Runnable> workQueue) {
6         this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
7              Executors.defaultThreadFactory(), defaultHandler);
8     }

 

  corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。

  maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。

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

  TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

   runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。

    ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。

    LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。

    SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。

    PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

  ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

  RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。

    AbortPolicy:直接抛出异常。

    CallerRunsPolicy:只用调用者所在线程来运行任务。

    DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。

    DiscardPolicy:不处理,丢弃掉。

    当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。

 

Java通过Executors提供四种线程池,分别为:
  newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

  newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

  newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

  newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

  他们的底层都是ThreadPoolExecutor。


newFixedThreadPool :

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

  corePoolSize和maximumPoolSize的大小是一样的,因为如果使用无界queue的话maximumPoolSize参数是没有意义的

  BlockingQueue选择了LinkedBlockingQueue,该queue有一个特点,他是无界的。

 

 1 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
 2 for (int i = 0; i < 10; i++) {
 3     final int index = i;
 4     fixedThreadPool.execute(new Runnable() {
 5 
 6         @Override
 7         public void run() {
 8             try {
 9                 System.out.println(index);
10                 Thread.sleep(2000);
11             } catch (InterruptedException e) {
12                 // TODO Auto-generated catch block
13                 e.printStackTrace();
14             }
15         }
16     });
17 }

  因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。

  定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()。

 

newSingleThreadExecutor:

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

  相当于newFixedThreadPool(1)

 

 1 ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
 2 for (int i = 0; i < 10; i++) {
 3     final int index = i;
 4     singleThreadExecutor.execute(new Runnable() {
 5 
 6         @Override
 7         public void run() {
 8             try {
 9                 System.out.println(index);
10                 Thread.sleep(2000);
11             } catch (InterruptedException e) {
12                 // TODO Auto-generated catch block
13                 e.printStackTrace();
14             }
15         }
16     });
17 }

  结果依次输出,相当于顺序执行各个任务。

  现行大多数GUI程序都是单线程的。

 

newCachedThreadPool:

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

  首先是无界的线程池,所以我们可以发现maximumPoolSize为max。其次BlockingQueue的选择上使用SynchronousQueue:每个插入操作必须等待另一个线程的对应移除操作。

  比如,我先添加一个元素,接下来如果继续想尝试添加则会阻塞,直到另一个线程取走一个元素,反之亦然。(就是缓冲区为1的生产者消费者模式)

 

 1 ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
 2 for (int i = 0; i < 10; i++) {
 3     final int index = i;
 4     try {
 5         Thread.sleep(index * 1000);
 6     } catch (InterruptedException e) {
 7         e.printStackTrace();
 8     }
 9 
10     cachedThreadPool.execute(new Runnable() {
11 
12         @Override
13         public void run() {
14             System.out.println(index);
15         }
16     });
17 }

  线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。

 

newScheduledThreadPool:

1     public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
2         return new ScheduledThreadPoolExecutor(corePoolSize);
3     }
4 
5     public ScheduledThreadPoolExecutor(int corePoolSize) {
6         super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
7               new DelayedWorkQueue());
8     }

 

1 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
2 scheduledThreadPool.schedule(new Runnable() {
3 
4     @Override
5     public void run() {
6         System.out.println("delay 3 seconds");
7     }
8 }, 3, TimeUnit.SECONDS);

  表示延迟3秒执行。

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

    @Override
    public void run() {
        System.out.println("delay 1 seconds, and excute every 3 seconds");
    }
}, 1, 3, TimeUnit.SECONDS);

  表示延迟1秒后每3秒执行一次。

  ScheduledExecutorService比Timer更安全,功能更强大,

Java线程池

标签:available   gui   结构   dex   body   jdk1.5   catch   final   活动   

原文地址:https://www.cnblogs.com/mengchunchen/p/8159024.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!