项目中Java的多线程一般用在哪些场景?

  • 多线程使用的主要目的在于
  • 举个简单的例子
  • 伪代码
  • 多线程的常见应用场景

多线程使用的主要目的在于

1、吞吐量:你做WEB,容器帮你做了多线程,但是他只能帮你做请求层面的。简单的说,可能就是一个请求一个线程。或多个请求一个线程。如果是单线程,那同时只能处理一个用户的请求。

2、伸缩性:也就是说,你可以通过增加CPU核数来提升性能。如果是单线程,那程序执行到死也就利用了单核,肯定没办法通过增加CPU核数来提升性能。

鉴于是做WEB的,第1点可能你几乎不涉及。那这里我就讲第二点吧。


举个简单的例子

假设有个请求,这个请求服务端的处理需要执行3个很缓慢的IO操作(比如数据库查询或文件查询),那么正常的顺序可能是(括号里面代表执行时间):

  1. 读取文件1 (10ms)
  2. 处理1的数据(1ms)
  3. 读取文件2 (10ms)
  4. 处理2的数据(1ms)
  5. 读取文件3 (10ms)
  6. 处理3的数据(1ms)
  7. 整合1、2、3的数据结果 (1ms)

单线程总共就需要34ms。

那如果你在这个请求内,把ab、cd、ef分别分给3个线程去做,就只需要12ms了。

所以多线程不是没怎么用,而是,你平常要善于发现一些可优化的点。然后评估方案是否应该使用。假设还是上面那个相同的问题:但是每个步骤的执行时间不一样了。

  1. 读取文件1 (1ms)
  2. 处理1的数据(1ms)
  3. 读取文件2 (1ms)
  4. 处理2的数据(1ms)
  5. 读取文件3 (28ms)
  6. 处理3的数据(1ms)
  7. 整合1、2、3的数据结果 (1ms)

单线程总共就需要34ms。

如果还是按上面的划分方案(上面方案和木桶原理一样,耗时取决于最慢的那个线程的执行速度),在这个例子中是第三个线程,执行29ms。那么最后这个请求耗时是30ms。比起不用单线程,就节省了4ms。但是有可能线程调度切换也要花费个1、2ms。因此,这个方案显得优势就不明显了,还带来程序复杂度提升。不太值得。

那么现在优化的点,就不是第一个例子那样的任务分割多线程完成。而是优化文件3的读取速度。可能是采用缓存和减少一些重复读取。

首先,假设有一种情况,所有用户都请求这个请求,那其实相当于所有用户都需要读取文件3。那你想想,100个人进行了这个请求,相当于你花在读取这个文件上的时间就是28×100=2800ms了。那么,如果你把文件缓存起来,那只要第一个用户的请求读取了,第二个用户不需要读取了,从内存取是很快速的,可能1ms都不到。


伪代码

 public class MyServlet extends Servlet{private static Map<String, String> fileName2Data = new HashMap<String, String>();private void processFile3(String fName){String data = fileName2Data.get(fName);if(data==null){data = readFromFile(fName);    //耗时28msfileName2Data.put(fName, data);}//process with data}}

看起来好像还不错,建立一个文件名和文件数据的映射。如果读取一个map中已经存在的数据,那么就不不用读取文件了。

可是问题在于,Servlet是并发,上面会导致一个很严重的问题,死循环。因为,HashMap在并发修改的时候,可能是导致循环链表的构成!!!(具体你可以自行阅读HashMap源码)如果你没接触过多线程,可能到时候发现服务器没请求也巨卡,也不知道什么情况!

好的,那就用ConcurrentHashMap,正如他的名字一样,他是一个线程安全的HashMap,这样能轻松解决问题。

 public class MyServlet extends Servlet{private static ConcurrentHashMap<String, String> fileName2Data = new ConcurrentHashMap<String, String>();private void processFile3(String fName){String data = fileName2Data.get(fName);if(data==null){data = readFromFile(fName);    //耗时28msfileName2Data.put(fName, data);}//process with data}}

这样真的解决问题了吗,这样虽然只要有用户访问过文件a,那另一个用户想访问文件a,也会从fileName2Data中拿数据,然后也不会引起死循环。

可是,如果你觉得这样就已经完了,那你把多线程也想的太简单了,骚年!你会发现,1000个用户首次访问同一个文件的时候,居然读取了1000次文件(这是最极端的,可能只有几百)。What the fuckin hell!!!

难道代码错了吗,难道我就这样过我的一生!

好好分析下。Servlet是多线程的,那么

 public class MyServlet extends Servlet{private static ConcurrentHashMap<String, String> fileName2Data = new ConcurrentHashMap<String, String>();private void processFile3(String fName){String data = fileName2Data.get(fName);//“偶然”-- 1000个线程同时到这里,同时发现data为nullif(data==null){data = readFromFile(fName);    //耗时28msfileName2Data.put(fName, data);}//process with data}}

上面注释的“偶然”,这是完全有可能的,因此,这样做还是有问题。

因此,可以自己简单的封装一个任务来处理。

 public class MyServlet extends Servlet{private static ConcurrentHashMap<String, FutureTask> fileName2Data = new ConcurrentHashMap<String, FutureTask>();private static ExecutorService exec = Executors.newCacheThreadPool();private void processFile3(String fName){FutureTask data = fileName2Data.get(fName);//“偶然”-- 1000个线程同时到这里,同时发现data为nullif(data==null){data = newFutureTask(fName);FutureTask old = fileName2Data.putIfAbsent(fName, data);if(old==null){data = old;}else{exec.execute(data);}}String d = data.get();//process with data}private FutureTask newFutureTask(final String file){return  new FutureTask(new Callable<String>(){public String call(){return readFromFile(file);}private String readFromFile(String file){return "";}}}}

以上所有代码可以直接运行。

多线程最多的场景:web服务器本身;各种专用服务器(如游戏服务器);


多线程的常见应用场景

  1. 后台任务,例如:定时向大量(100w以上)的用户发送邮件;
  2. 异步处理,例如:发微博、记录日志等;
  3. 分布式计算

项目中Java的多线程一般用在哪些场景?相关推荐

  1. java定时任务中使用多线程_java项目中如何利用多线程实现一个定时器任务

    java项目中如何利用多线程实现一个定时器任务 发布时间:2020-11-10 16:04:03 来源:亿速云 阅读:86 作者:Leah 今天就跟大家聊聊有关java项目中如何利用多线程实现一个定时 ...

  2. php7开发的项目怎么样,如何在PHP7项目中搭建一个多线程

    如何在PHP7项目中搭建一个多线程 发布时间:2021-03-05 15:31:22 来源:亿速云 阅读:93 作者:Leah 这期内容当中小编将会给大家带来有关如何在PHP7项目中搭建一个多线程,文 ...

  3. Spring Boot 项目中Java对象的字符串类型属性值转换为JSON对象的布尔类型键值的解决方法及过程

    文章目录 场景描述 示例说明 解决历程 @JsonFormat是否能解决问题? 万能方案-调试 替代方案 补充知识 Java对象与JSON对象的序列化与反序列化 相关注解说明 后记 场景描述 在Spr ...

  4. was java heap space_实战项目中Java heap space错误的解决

    部标GPS通讯系统在上线之后,经过不断调试,终于稳定运行一段时间,后来又遇到了Java heap space错误异常!日志如下: 说明系统中有未释放的对象.如何找出这些未释放对象以及监控JVM堆内存, ...

  5. 关于IDEA项目中Java文件夹下不能建立package文件的问题

    今天建项目突然发现不能创建package文件夹和class文件,后来仔细看了看发现src\main下的java文件显示不是正常的蓝色.以前发现过这种情况.今天记录一下..... 在File菜单选择以下 ...

  6. spring JdbcTemplate 在项目中的浅层(5个使用场景)封装

    导读: 主要从4个方面来阐述,1:背景:2:思路:3:代码实现:4:使用 一:封装背景, 在做项目的时候,用的JPA ,有些复杂查询,比如报表用原生的JdbcTemplate ,很不方便,传参也不方便 ...

  7. antvl7绘制地图以及vue项目中使用多线程worker

    vue项目中如何使用多线程worker 项目背景:写一个定时器计时,但是和另外一个计时器产生事件循环问题,导致计时不准,所以把计时器放到另外一个线程里,避免两个计时器及渲染冲突 1.安装worker- ...

  8. java通信项目_Java项目中的多线程通信如何利用Socket实现

    Java项目中的多线程通信如何利用Socket实现 发布时间:2020-11-24 16:44:40 来源:亿速云 阅读:96 作者:Leah 这期内容当中小编将会给大家带来有关Java项目中的多线程 ...

  9. java socket建立长连接_Java Web项目中使用Socket通信多线程、长连接的方法

    很多时候在javaweb项目中我们需要用到Socket通信来实现功能,在web中使用Socket我们需要建立一个监听程序,在程序启动时,启动socket监听.我们的应用场景是在java项目中,需要外接 ...

最新文章

  1. JavaScript - this详解 (三)
  2. 移动开发还有未来吗?
  3. java fx dialog_JavaFX 如何使用內建的對話框(Dialog)?
  4. css实现web前端最美的loading加载动画!
  5. 眼液蛋白水平或许可预测阿尔茨海默症
  6. 2022年3月Python小屋编程比赛获奖名单
  7. 数据仓库和数据挖掘复习
  8. 使用echarts实现半圆饼图
  9. ADS 修改版图默认单位
  10. php丢色子,jQuery+PHP实现的掷色子抽奖游戏实例_PHP
  11. 操作系统 文件换行符问题
  12. 《红楼梦》的香气韵调
  13. idea导入项目后简体字变繁体字
  14. 量化指标公式源码_量化指标副图指标 源码 通达信 贴图 无未来
  15. 数据库设置定期删除14天前的数据
  16. 浅析GPU计算——CPU和GPU的选择
  17. Java 8 新特性 lambda表达式
  18. 超长浮点数据到科学计数法的转换
  19. 如何利用计算机班级成绩分析,北京自考计算机应用基础课成绩分析报告
  20. 山西思诺腾讯云架构工程师TCA认证如何考取

热门文章

  1. 原理这就是索引下推呀
  2. STM32F4_外部中断详解(EXTI)
  3. Element2 el-tooltip 滚动时 不消失
  4. 实验四 串行通信实验
  5. 天津大学计算机课程设计挂,天津大学智能装置课程设计 电子时钟..doc
  6. java google map_java如何通过google map api实现地址解析
  7. win10计算机无法搜索,win10搜索框没反应怎么办_win10电脑搜索框点击无反应如何解决...
  8. 2015年09月29日
  9. Spring Boot 2.0 配置图文教程
  10. Android SnackBar