Java5相比之前的Java版本,在并发编程上,有了非常大的提高,加了很多类,提供了很多可用于并发编程的工具包和工具类。尤其为人们所称道的,就是Java自带的线程池。
Java5线程池的介绍文章,可以说在网上比比皆是,我就不再重复了,只是简单提一下,线程池给并发程序带 来了几个好处:
1、创建和销毁线程的开销
2、保护系统资源,避免创建太多的线程导致系统崩溃
3、简化编程模型
Java5自带的线程池( ThreadPool),用于并发系统的,主要有:
缓存线程池(newCachedThreadPool):每个任务过来后都会创建一个线程,任务结束后,线程缓存一段时间,下次任务过来后,如果有之前缓存的线程就无须再创建而是直接使用。
固定数量线程池(newFixedThreadPool):创建固定线程数量的线程池,如果任务数大于线程池中线程的数量,那么任务将等待。
其实,我们看Java的源代码,就会发现,上面两种线程池,都是调用Java的ThreadPoolExecutor来实现的。其构造函数如下:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) |
我们可以看到,实际上是需要制定核心线程数、最大线程数、存活时间和时间单位、选择的队列这些参数。
其中,核心线程数的概念至关重要,当有任务到来时,如果线程池中的线程数还不够核心线程数,则启动一个新的线程来运行任务(即便其它线程在空闲);如果线程池中的线程已经达到核心数,但未达到最大数,则任务放到队列中等待空闲的核心线程处理;除非队列满,不会启动新的线程。
从这里,我们再来看缓存线程池和固定数量线程池,非常简单能够看出,缓存线程池的核心数为1,最大数为1,队列长度是1;固定线程池核心数和最大数都是设定的数量。
因为Java提供了这两种线程池,所以一般情况下,我们可能都觉得不需要再写别的线程池实现了,直接用这两种吧。结果在产品开发的过程中,笔者就遇到了很大的一个坑,差点掉进去出不来。
当时是要开发一款高性能、高稳定性的C/S模式的服务器产品,Java5之后,使用线程池改进了任务派发的部分,当时以为这两种线程池都应该能够满足要求,就先采用固定数量线程池来试,结果发现如果服务器和客户端都采用长连接,固定数量线程池存在很大的设计上的bug。
例如任务线程池核心数100,最大数100,客户端也正好100个连接连上了服务器。因为长连接机制下,为了保证处理效率,流程是服务器端ServerSocket在accept之后,不停循环,接受到请求后处理,然后继续等待连接上的数据,直至接收到客户端断开的指令或服务器端超时。
如下图:
可以想象,如果这时候第101个连接连上了服务器,再没有新的连接,TCP连接正常,任务也被接受放到了队列里,那么这个任务就只能乖乖等在队列里等着超时,别的什么都做不了!除非改变上面流程图中的方式,线程不再这样循环,而是直接返回,这个连接上新的数据过来由另外的线程处理,等待线程池重新分配,但这样效率一定不如图中的方式好,否则没有什么好的办法。
对于一些使用场景复杂的服务器端,客户端长连接和短连接都可能有的这种场景,使用固定大小线程池,就必须考虑这个问题。或者牺牲效率,或者深入考虑长连线程带来的问题。
既然固定大小有问题,那就看看缓存线程池吧,麻烦更大了,如果服务器没有别的辅助控制,一下子涌入大量的客户连接,服务器一下子需要启动大量的线程,很有可能崩溃,这个也是无法接受的。
从这里可以看到,Java自带的两种线程池,其实是各有各自的适用场景,对池中的任务,也都有自己的要求和限制,在适用这些基础设施来设计系统之前,首先应该对这些进行透彻的分析,不要等到出现bug才醒悟。上面提到的bug,因为没有清晰的错误信息,就非常不容易分析出来。
如果你的服务器面临这么复杂多变的客户端,而且既要求效率上不能牺牲,又希望使用Java的线程基础设施,那么一定要在这里慎重再慎重。
相关推荐
互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术,人工智能互联网资讯,技术简介,IT、AI技术...
加密的惨剧!慎用文件夹加密软件! 加密的惨剧!慎用文件夹加密软件!
因此,当面临代码复用需求时,应优先考虑聚合和组合这两种设计模式。 聚合和组合是比继承更灵活的代码复用方式。在聚合关系中,一个对象(容器)包含另一个对象(组件),但两者之间不存在所有权关系,如`...
java的file rename方法 以前我一直以为File#renameTo(File)方法与OS下面的 move/mv 命令是相同的,可以达到改名、移动文件的目的。不过后来经常发现问题:File#renameTo(File)方法会返回失败(false),文件没有移动,...
把要删除的文件拖到这个文件上面即可。注意,这是强力删除。一定慎用,因为连垃圾箱都会没有的。
JavaFX是Java平台上的一个强大的用户界面工具包,用于创建...但是,由于标题中提到“有待完善,慎用”,说明这个项目可能还在开发阶段,可能存在一些未解决的问题,因此在使用时需要谨慎,可能需要进一步完善和调试。
站长助手相关代码,里面有一点注入代码,慎用!!!
封装的iocp,线程池。效率很高,很实用,不包括发送队列,请自行处理。最大支持1w个sock 解决内存泄露问题 增加accept线程个数,调整返回参数值 ...备注:本次优化针对pt系列汇编指令集,amd慎用 源码不提供
遇到加密光盘怎么办?里面的东西拷贝不出来怎么办?使用Isobuster帮你解决这个问题!慎用!!!!!!注意版权。
易语言处理事件命令慎用时钟版源码,处理事件命令慎用时钟版
放在仓库目录下,直接双击运行,自动获取目录,自动清理删除本文件夹下所有包含"lastUpdated,*.repositories,*.sha1-in-progress" 的文件。请慎用。!!!!!!
2. 慎用反序列化。在不必要的时候避免反序列化操作,或者严格限制和监控反序列化的数据来源。 3. 使用安全的反序列化实践。例如,使用白名单过滤器来限制可以反序列化的类,避免执行未经验证的输入数据。 4. 采用...
标题“慎用动态编译”指的是在编程过程中对动态编译这一技术的谨慎态度。动态编译是程序运行时根据需要将源代码编译为可执行代码的过程,与静态编译(编译时一次性完成)形成对比。在Java中,JIT(Just-In-Time)...
推荐使用List接口,慎用Vector,优先选择ArrayList和LinkedList。 三、并发编程 1. 并发控制:正确使用synchronized、volatile,理解并发工具类如Semaphore、CyclicBarrier等。避免并发修改集合,提倡使用并发容器...
- **慎用`GetStringCritical`**:由于它可能导致GC暂停,因此只应在没有内存分配和阻塞操作的短时间段内使用。 在上述示例中,由于`fprintf`可能触发I/O操作,这会阻塞系统,因此在使用`GetStringCritical`后调用它...
preserve_c_code_attention!!!_在linux下请慎用rm命令_删除了一堆代_c_code
本工具用批处理所写 然后通过exescript转换了一下 意在交流 运行“金太阳”会在每个盘符创建顽固文件夹。 运行“jintaiyang”会针对性的删除。...慎用!!!!!!!! echo echo echo echo echo echo echo
- **慎用反射**:反射操作通常比直接调用方法慢,尽量减少反射的使用。 - **元数据缓存**:使用Class.getDeclaredMethods等方法时,可以缓存结果以提高性能。 8. **监控与分析**: - **使用JVisualVM**:这是一...
本资源适合已有java基础,但稍微有点忘记的人群,对于初学者可能不够全面,慎下!!!! 本资源中的思维导图为xmind编写,是自己看《Java从入门到精通》时所画的思维导图,由于看完之后感悟不深,后序笔记未整理,只...
SQL和MSDE清理小程序(慎用),SQL和MSDE清理小程序(慎用),SQL和MSDE清理小程序(慎用),