Java多线程_线程池
作用
我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:
如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。
那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?
在Java中可以通过线程池来达到这样的效果。
线程池的作用:
- 线程可以重复利用;
- 减少创建和销毁线程所带来的系统资源的开销;
- 提升性能(节省线程创建的时间开销,使程序响应更快)。
常见的线程池
JDK1.5之后,提供了四种线程池:
- 固定线程数的线程池(newFixedThreadPool)
- 缓存的线程池(newCachedThreadPool)
- 单个线程的线程池(newSingleThreadExecutor)
- 固定个数的线程池(newScheduledThreadPool)
下面分别说说这四个线程池:
(1)固定线程数的线程池(newFixedThreadPool):
这种线程池里面的线程被设计成存放固定数量的线程,具体线程数可以考虑为CPU核数*N(N可大可小,取决于并发的线程数,计算机可用的硬件资源等)。可以通过下面的这条代码获取当前计算机的CPU的核数。
int processors = Runtime.getRuntime().availableProcessors();
FixedThreadPool 是通过 java.util.concurrent.Executors 创建的 ThreadPoolExecutor 实例。这个实例会复用 固定数量的线程处理一个共享的无边界队列 。任何时间点,最多有 nThreads 个线程会处于活动状态执行任务。如果当所有线程都是活动时,有多的任务被提交过来,那么它会一致在队列中等待直到有线程可用。如果任何线程在执行过程中因为错误而中止,新的线程会替代它的位置来执行后续的任务。
使用ExecutorService.shutdown() 可以关闭线程池。由于使用了LinkedBlockingQueue,是一个无界队列,因此永远不可能拒绝任务。LinkedBlockingQueue在入队列和出队列时使用的是不同的Lock,意味着他们之间不存在互斥关系,在多CPU情况下,他们能正在在同一时刻既消费,又生产,真正做到并行。因此这种线程池不会拒绝任务,而且不会开辟新的线程,也不会因为线程的长时间不使用而销毁线程。这是典型的生产者----消费者问题,这种线程池适合用在稳定且固定的并发场景,比如服务器。下面代码给出一个示例:
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Test {
public static void main(String[] args) {
// 获取计算机有几个核
int processors = Runtime.getRuntime().availableProcessors(); // 第一种线程池:固定个数的线程池,可以为每个CPU核绑定一定数量的线程数
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(processors * 5); for (int i = 0; i < 10; i++) {
fixedThreadPool.execute(new Runnable() { @Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
fixedThreadPool.shutdown();
}
}
(2)缓存的线程池(newCachedThreadPool)
核心池大小为0,线程池最大线程数目为最大整型,这意味着所有的任务一提交就会加入到阻塞队列中。当线程池中的线程60秒没有执行任务就终止,阻塞队列为SynchronousQueue。SynchronousQueue的take操作需要put操作等待,put操作需要take操作等待,否则会阻塞,而线程池的阻塞队列不能存储,所以当目前线程处理忙碌状态时,所以开辟新的线程来处理请求。
它是一个可以无限扩大的线程池,适合处理执行时间比较小的任务,如果主线程提交任务的速度远远大于CachedThreadPool的处理速度,则CachedThreadPool会不断地创建新线程来执行任务,这样有可能会导致系统耗尽CPU和内存资源,所以在使用这种线程池时,一定要注意控制并发的任务数,否则创建大量的线程可能导致严重的性能问题。
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Test {
public static void main(String[] args) {
// 缓存线程池,无上限
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
cachedThreadPool.shutdown();
}
}
(3)单个线程的线程池(newSingleThreadExecutor)
SingleThreadExecutor是使用单个worker线程的Executor,作为单一worker线程的线程池,SingleThreadExecutor把corePool和maximumPoolSize均被设置为1,和FixedThreadPool一样使用的是无界队列LinkedBlockingQueue,所以带来的影响和FixedThreadPool一样。
对于newSingleThreadExecutor()来说,也是当线程运行时抛出异常的时候会有新的线程加入线程池替他完成接下来的任务。创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行,所以这个比较适合那些需要按序执行任务的场景。比如:一些不太重要的收尾工作,日志等工作可以放到单线程的线程中去执行。
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Test {
public static void main(String[] args) {
// 单一线程池,永远会维护存在一条线程
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int j = i;
singleThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + j);
}
});
}
singleThreadPool.shutdown(); }
}
(4)固定个数的线程池(newScheduledThreadPool)
与newFixedThreadPool线程池很像,但它更强大:
- 可以执行延时任务,
- 也可以执行带有返回值的任务。
import java.util.concurrent.*;
public class Test {
public static void main(String[] args) throws InterruptedException, ExecutionException{
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
FutureTask<String> ft = new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("hello");
return Thread.currentThread().getName();
}
});
scheduledThreadPool.submit(ft);
String result = ft.get();
System.out.println("result : " + result);
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " : bobm!");
}
}, 3L, TimeUnit.SECONDS);
}
}
Java多线程_线程池的更多相关文章
- java ->多线程_线程池
线程池概念 线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源. 我们详细的解释一下为什么要使用线程池?(程序优化) 在jav ...
- Java多线程与线程池技术
一.序言 Java多线程编程线程池被广泛使用,甚至成为了标配. 线程池本质是池化技术的应用,和连接池类似,创建连接与关闭连接属于耗时操作,创建线程与销毁线程也属于重操作,为了提高效率,先提前创建好一批 ...
- Java 多线程:线程池
Java 多线程:线程池 作者:Grey 原文地址: 博客园:Java 多线程:线程池 CSDN:Java 多线程:线程池 工作原理 线程池内部是通过队列结合线程实现的,当我们利用线程池执行任务时: ...
- java多线程、线程池及Spring配置线程池详解
1.java中为什么要使用多线程使用多线程,可以把一些大任务分解成多个小任务来执行,多个小任务之间互不影像,同时进行,这样,充分利用了cpu资源.2.java中简单的实现多线程的方式 继承Thread ...
- Java多线程和线程池
转自:http://blog.csdn.net/u013142781/article/details/51387749 1.为什么要使用线程池 在Java中,如果每个请求到达就创建一个新线程,开销是相 ...
- Java多线程之线程池详解
前言 在认识线程池之前,我们需要使用线程就去创建一个线程,但是我们会发现有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因 ...
- JAVA多线程(三) 线程池和锁的深度化
github演示代码地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/spb-brian-query-servic ...
- Java多线程-ThreadPool线程池(三)
开完一趟车完整的过程是启动.行驶和停车,但老司机都知道,真正费油的不是行驶,而是长时间的怠速.频繁地踩刹车等动作.因为在速度切换的过程中,发送机要多做一些工作,当然就要多费一些油. 而一个Java线程 ...
- java 多线程 4 线程池
系统启动一个新线程的成本是比较高的,因为它涉及到与操作系统的交互.在这种情况下,使用线程池可以很好的提供性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池. 与数据库连接池类似 ...
随机推荐
- (一) BIO,NIO, 阻塞,非阻塞,你懂了吗
一般来说,一个输入操作通常包括两个阶段: .等待数据准备好: .从内核向进程复制数据 是否同步的判断依据是: 是否 针对的 整个过程,即2个阶段,是否有阻塞 是否阻塞的判断依据是: 按 程序等待消息通 ...
- Django学习路30_view中存在重复名时,取第一个满足条件的
在 settings 中添加 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.con ...
- 11-13 模块_collections(不太重要)&time&random&os
random:随机数模块 os:和操作系统打交道的模块 sys:和Python解释器打交道的模块 序列化模块:Python中的数据类型和str转换的模块 http://www.cnblogs.com/ ...
- Hadoop学习问题记录之基础篇
目的 记录学习hadoop过程中遇到的基础问题,无关大小.无关困扰时间长短. 问题一 全分布式环境中运行mapred程序,报异常:java.net.NoRouteToHostException: 没有 ...
- LVS-DR实现mysql负载均衡集群
lvs-dr实现mysql负载均衡集群 环境说明: 服务器的操作系统均为centos7,vip和rip在同一网段,使用lvs-dr模型来实现mysql集群服务 所有服务器均已配置好处VIP外的静态IP ...
- node日志管理 / pm2-logrotate-ext日志管理
本篇文章说的是,如何使用pm2管理node项目的日志输出(切割和备份),文章步骤是基于已经安装了pm2的前提下,没有的,请自行百度. 第一步:需要登录公司服务器,查看一下目前服务器保存的所有日志(用于 ...
- three.js 着色器材质基础(一)
说起three.js,着色器材质总是绕不过的话题,今天郭先生就说一说什么是着色器材质.着色器材质是很需要灵感和数学知识的,可以用简短的代码和绘制出十分丰富的图像,可以说着色器材质是脱离three.js ...
- 打造静态分析器(二)基于Asp.Net Core 3.0的AspectCore组件检测
上一篇,我们打造了一个简单的分析器,但是我们实际使用分析器就是为了对项目做分析检测,增加一些非语法的自检的 比如Asp.Net Core 3.0的替换依赖注入检测 设计分析 我们创建一个默认的Asp. ...
- Linux操作系统 可插拔认证模块PAM(3)
六.Linux 操作系统安全登陆设计 自己编写PAM 模块并编译成动态链接库so 文件,将其添加进/etc/pam.d/login 文件中实现命令行安全登陆设计,将其添加进/etc/pam.d/lig ...
- Python利用Twilio(国际)以及腾讯云服务做一些事情
短信服务验证服务已经不是什么新鲜事了,但是免费的手机短信服务却不多见,本次利用Python3.0基于Twilio和腾讯云服务分别来体验一下国际短信和国内短信接口. 首先,注册Twilio: www.t ...