Java线程池
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java线程池,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5479字,纯文字阅读大概需要8分钟。
内容图文
new Thread的弊端:
1 new Thread(new Runnable() { 23 @Override 4publicvoid run() { 5// TODO Auto-generated method stub6 } 7 }).start();
new Thread的弊端如下:
a. 每次new Thread新建对象性能差。
b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
c. 缺乏更多功能,如定时执行、定期执行、线程中断。
相比new Thread,Java提供的四种线程池的好处在于:
a. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
b. 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
c. 高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
可以通过ThreadPoolExecutor来创建一个线程池:
1 public ThreadPoolExecutor(int corePoolSize, 2int maximumPoolSize, 3long keepAliveTime, 4 TimeUnit unit, 5 BlockingQueue<Runnable> workQueue) { 6this(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) { 2returnnew ThreadPoolExecutor(nThreads, nThreads, 3 0L, TimeUnit.MILLISECONDS, 4new LinkedBlockingQueue<Runnable>()); 5 }
corePoolSize和maximumPoolSize的大小是一样的,因为如果使用无界queue的话maximumPoolSize参数是没有意义的
BlockingQueue选择了LinkedBlockingQueue,该queue有一个特点,他是无界的。
1 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); 2for (int i = 0; i < 10; i++) { 3finalint index = i; 4 fixedThreadPool.execute(new Runnable() { 5 6 @Override 7publicvoid run() { 8try { 9 System.out.println(index); 10 Thread.sleep(2000); 11 } catch (InterruptedException e) { 12// TODO Auto-generated catch block13 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, 5new LinkedBlockingQueue<Runnable>())); 6 }
相当于newFixedThreadPool(1)
1 ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); 2for (int i = 0; i < 10; i++) { 3finalint index = i; 4 singleThreadExecutor.execute(new Runnable() { 5 6 @Override 7publicvoid run() { 8try { 9 System.out.println(index); 10 Thread.sleep(2000); 11 } catch (InterruptedException e) { 12// TODO Auto-generated catch block13 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, 4new SynchronousQueue<Runnable>()); 5 }
首先是无界的线程池,所以我们可以发现maximumPoolSize为max。其次BlockingQueue的选择上使用SynchronousQueue:每个插入操作必须等待另一个线程的对应移除操作。
比如,我先添加一个元素,接下来如果继续想尝试添加则会阻塞,直到另一个线程取走一个元素,反之亦然。(就是缓冲区为1的生产者消费者模式)
1 ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); 2for (int i = 0; i < 10; i++) { 3finalint index = i; 4try { 5 Thread.sleep(index * 1000); 6 } catch (InterruptedException e) { 7 e.printStackTrace(); 8 } 910 cachedThreadPool.execute(new Runnable() { 1112 @Override 13publicvoid run() { 14 System.out.println(index); 15 } 16 }); 17 }
线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
newScheduledThreadPool:
1 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { 2returnnew ScheduledThreadPoolExecutor(corePoolSize); 3 } 45public ScheduledThreadPoolExecutor(int corePoolSize) { 6super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, 7new DelayedWorkQueue()); 8 }
1 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); 2 scheduledThreadPool.schedule(new Runnable() { 34 @Override 5publicvoid run() { 6 System.out.println("delay 3 seconds"); 7 } 8 }, 3, TimeUnit.SECONDS);
表示延迟3秒执行。
scheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Override publicvoid run() { System.out.println("delay 1 seconds, and excute every 3 seconds"); } }, 1, 3, TimeUnit.SECONDS);
表示延迟1秒后每3秒执行一次。
ScheduledExecutorService比Timer更安全,功能更强大,
原文:https://www.cnblogs.com/mengchunchen/p/8159024.html
内容总结
以上是互联网集市为您收集整理的Java线程池全部内容,希望文章能够帮你解决Java线程池所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。