多线程使用的主要目的在于:1、吞吐量:你做WEB,容器帮你做了多线程,但是他只能帮你做请求层面的。简单的说,可能就是一个请求一个线程。或多个请求一个线程。如果是单线程,那同时只能处理一个用户的请求。2、伸缩性:也就是说,你可以通过增加CPU核数来提升性能。如果是单线程,那程序执行到死也就利用了单核,肯定没办法通过增加CPU核数来提升性能。
鉴于是做WEB的,第1点可能你几乎不涉及。那这里我就讲第二点吧。fileName2Data=newHashMap(); privatevoidprocessFile3(StringfName){ Stringdata=fileName2Data.get(fName); if(data==null){ data=readFromFile(fName);//耗时28ms fileName2Data.put(fName,data); } //processwithdata } }
看起来好像还不错,建立一个文件名和文件数据的映射。如果读取一个map中已经存在的数据,那么就不不用读取文件了。
可是问题在于,Servlet是并发,上面会导致一个很严重的问题,死循环。因为,HashMap在并发修改的时候,可能是导致循环链表的构成!!!(具体你可以自行阅读HashMap源码)如果你没接触过多线程,可能到时候发现服务器没请求也巨卡,也不知道什么情况!
好的,那就用ConcurrentHashMap,正如他的名字一样,他是一个线程安全的HashMap,这样能轻松解决问题。fileName2Data=newConcurrentHashMap(); privatevoidprocessFile3(StringfName){ Stringdata=fileName2Data.get(fName); if(data==null){ data=readFromFile(fName);//耗时28ms fileName2Data.put(fName,data); } //processwithdata } }
这样真的解决问题了吗,这样虽然只要有用户访问过文件a,那另一个用户想访问文件a,也会从fileName2Data中拿数据,然后也不会引起死循环。最新 Java 面试题出炉!分享给你。
可是,如果你觉得这样就已经完了,那你把多线程也想的太简单了,骚年!你会发现,1000个用户首次访问同一个文件的时候,居然读取了1000次文件(这是最极端的,可能只有几百)。What the ***in hell!!!
难道代码错了吗,难道我就这样过我的一生!
好好分析下。Servlet是多线程的,那么fileName2Data=newConcurrentHashMap(); privatevoidprocessFile3(StringfName){ Stringdata=fileName2Data.get(fName); //“偶然”--1000个线程同时到这里,同时发现data为null if(data==null){ data=readFromFile(fName);//耗时28ms fileName2Data.put(fName,data); } //processwithdata } }
上面注释的“偶然”,这是完全有可能的,因此,这样做还是有问题。
因此,可以自己简单的封装一个任务来处理。fileName2Data=newConcurrentHashMap(); privatestaticExecutorServiceexec=Executors.newCacheThreadPool(); privatevoidprocessFile3(StringfName){ FutureTaskdata=fileName2Data.get(fName); //“偶然”--1000个线程同时到这里,同时发现data为null if(data==null){ data=newFutureTask(fName); FutureTaskold=fileName2Data.putIfAbsent(fName,data); if(old==null){ data=old; }else{ exec.execute(data); } } Stringd=data.get(); //processwithdata } privateFutureTasknewFutureTask(finalStringfile){ returnnewFutureTask(newCallable(){ publicStringcall(){ returnreadFromFile(file); } privateStringreadFromFile(Stringfile){return"";} } } }
以上所有代码都是直接在bbs打出来的,不保证可以直接运行。
多线程最多的场景:web服务器本身;各种专用服务器(如游戏服务器);
举个简单的例子:
假设有个请求,这个请求服务端的处理需要执行3个很缓慢的IO操作(比如数据库查询或文件查询),那么正常的顺序可能是(括号里面代表执行时间):- 读取文件1 (10ms)
- 处理1的数据(1ms)
- 读取文件2 (10ms)
- 处理2的数据(1ms)
- 读取文件3 (10ms)
- 处理3的数据(1ms)
- 整合1、2、3的数据结果 (1ms)
- 读取文件1 (1ms)
- 处理1的数据(1ms)
- 读取文件2 (1ms)
- 处理2的数据(1ms)
- 读取文件3 (28ms)
- 处理3的数据(1ms)
- 整合1、2、3的数据结果 (1ms)
伪代码:
publicclassMyServletextendsServlet{ privatestaticMap
publicclassMyServletextendsServlet{ privatestaticConcurrentHashMap
publicclassMyServletextendsServlet{ privatestaticConcurrentHashMap
publicclassMyServletextendsServlet{ privatestaticConcurrentHashMap
审核编辑 :李倩
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
服务器
+关注
关注
12文章
8701浏览量
84563 -
JAVA
+关注
关注
19文章
2943浏览量
104107 -
多线程
+关注
关注
0文章
275浏览量
19850
原文标题:面试官:公司项目中Java的多线程一般用在哪些场景?
文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
多线程编程之一: 问题提出
:lpThreadAttributes:指向一个 SECURITY_ATTRIBUTES 结构的指针,该结构决定了线程的安全属性,一般置为 NULL; dwStackSize:指定了线程
发表于 10-22 11:41
Java一直独得恩宠的秘诀
Java中没有指针,这样就没有办法直接访问内存了。另外Java也不容易出现内存泄露。而且Java确实有很多企业在用,都是用在大项目上。这就意
发表于 09-28 14:24
java多线程编程实例 (源程序)
java多线程编程实例
import java.awt.*;import javax.swing.*;
public class CompMover extends Object { 
发表于 10-22 11:48
•0次下载
java多线程设计模式_结城浩
《JAVA多线程设计模式》通过浅显易懂的文字与实例来介绍JAVA线程相关的设计模式概念,并且通过实际的JAVA程序范例和UML图示来一一解说
发表于 01-05 16:15
•0次下载
Java多线程总结之Queue
在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列。Java提供的线程安全的Queue可以分为 阻塞队列和非阻塞队列 ,其中阻塞队列的典型例子
发表于 11-28 16:14
•3246次阅读
涤纶电容一般用在哪里?
二者是有区别的!涤纶电容又叫聚酯电容符号为CL,电容量一般40p--4μ, 额定电压63--630V,主要特点体积小容量大耐热耐湿但稳定性差一般应用在对稳定性和损耗要求不高的低频电路。
发表于 11-13 09:51
•3943次阅读
Java多线程永动任务 多线程异步任务项目解读
, 这个示例的原型是公司自研的多线程异步任务项目 ,我把里面涉及到多线程的代码抽离出来,然后进行一定的改造。 里面涉及的知识点非常多,特别适
多线程编程可以应用在哪里?C++多线程详解
多线程并发指的是在同一个进程中执行多个线程。 优点: 有操作系统相关知识的应该知道,线程是轻量级的进程,每个线程可以独立的运行不同的指令序列
发表于 04-13 10:10
•618次阅读
纽扣型超级电容器一般是用在哪里?
纽扣型超级电容器一般是用在哪里?即便是同一种类型的产品,其型号、规格以及作用都是不同的。所以,大家在选择产品的时候,也要从细节方面来考虑。纽扣型超级电容器在市场上是很常见的,它被应用在
评论