文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

并发与高并发系列第一集-基础与概念

2024-12-03 03:32

关注

本文转载自微信公众号「安琪拉的博客」,作者安琪拉。转载本文请联系安琪拉的博客公众号。

面试官:看你简历上写,最近正在写并发编程方面的博客,是吧?

安琪拉:闲来无事,看看闲书,写写段子,承蒙读者厚爱,有此打算。

面试官:少跟我这拽文,“闲来无事”?阿里不用996吗?

安琪拉:修福报,你知道吗?..... 技术人的日常,能算996吗?

面试官:算了算了,还是聊正题,你先跟我讲讲什么是并发?

安琪拉:并发就是存在两个或多个线程,这些线程同时操作相同的物理机中的资源。

面试官:那并发跟并行有什么区别呢?

安琪拉:举个生活中的例子就懂了:

你在打王者荣耀,这个时候女朋友找你视频,你一直打完王者荣耀才接,说明你不支持并发(也不支持并行);

你在打王者荣耀,这个时候女朋友给你发了微信,你退出王者荣耀,回完微信再回到王者,微信和王者间来回切换,说明你支持并发,但不支持并行;

你在打王者荣耀,这个时候女朋友给你打电话,你边打荣耀边接电话,说明你支持并行。

并行的关键点是物理的“同时”,我们在单核CPU的时候,既能写代码也能听歌,这个多线程实际是基于操作系统根据CPU时间片做的任务轮转,是伪“同时”,只能说是并发,不能算并行,但是多核CPU可以支持每个核同时运行任务,是真实的“同时”,是并行。

Erlang 之父 Joe Armstrong 画了一张图解释了并发与并行的区别,Concurrent (并发),Parallel (并行)。

并发允许二队小孩轮流使用咖啡机,并行是同时存在二台咖啡机,二队小孩同时使用,不冲突。

面试官:那高并发呢?你了解高并发吗?

安琪拉:【心里想,该来的还是来了,要造火箭了】

你说High Concurrency(高并发)是吧(先拽句英文)。

通常我们谈论并发的时候,更多的关注点在于线程安全,但是讨论高并发时,关注点不仅仅是线程安全问题,而是如何在短时间内处理大量请求,保证系统响应时间和吞吐量的可靠,更多关注的是稳定性问题(SRE),高并发涉及的是完整的系统知识,线程安全只是其中一小部分。

高并发是现在互联网设计系统中需要考虑的一个重要因素之一,通常来说,就是通过严谨的设计来保证系统能够同时并行处理很多的请求。这就是大家常说的「 高并发 」。也就是说系统能够在某一时间段内提供很多请求,但是不会影响系统的性能。如果想设计出高可用和高性能的系统,就应该从很多的方面来考虑,例如应该从硬件、软件、编程语言的选择、网络方面的考虑、系统的整体架构、数据结构、算法的优化、数据库的优化等等多方面。这其中的每一点展开来说都要说很多的知识,安琪拉会在后续课程更新这部分内容。

面试官:那你跟我讲讲你们系统的QPS有多少?

安琪拉:大促场景能有个10W+的QPS,日常业务高峰期也有2W+,其他时间几千。

其实对于大部分的系统,几十、几百很正常,QPS能过千的就已经不低了,有的业务会有峰值,QPS稳定过万的系统实际中不多,所以大家日常可以关注一下自己系统的QPS,这个问题面试经常会问。

面试官:一般我们有什么工具可以模拟并发请求呢?

安琪拉:PostMan、Apache Bench(AB)、Jmeter,推荐使用Jmeter。

面试官:那你能写段代码,演示一下并发安全的问题吗?

安琪拉:可以啊。笔递给我一下,顺便帮我拿下A4纸。

  1. public class ConcurrencySafeTest { 
  2.  
  3.     private static int counter = 0; 
  4.  
  5.     public static void main(String[] args) { 
  6.         //使用线程池 
  7.         ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool(); 
  8.         //提交2000个任务 
  9.         for(int i = 0; i < 2000; i++) { 
  10.             threadPool.submit(new Add()); 
  11.         } 
  12.         threadPool.shutdown(); 
  13.         System.out.println(counter); 
  14.     } 
  15.  
  16.     static class Add implements Runnable { 
  17.         @Override 
  18.         public void run() { 
  19.             counter++; 
  20.         } 
  21.     } 

我们进行计数操作,执行2000次,预期的执行结果应该是2000,但是实际执行结果如下:

  1. 1971 
  2. 1987 

因为《并发》系列是从基础开始讲的,上面的代码部分内容涉及到后面的一些内容,比如线程池和线程的使用,这里只要大致了解并发的安全问题,后面会有详细说明,后面面试官的问题作为扩展阅读。

面试官:看到你代码中用了CachedThreadPool,那2000次任务执行,CachedThreadPool 线程池创建了多少个线程?

安琪拉:答案是不确定,CachedThreadPool 缓存了线程(复用线程),没有让任务排队,来一个任务,要么复用已有线程处理,要么新建一个线程处理。那我们怎么确定线程池创建过多少个线程呢?可以加一段代码打印出来。

如下:

  1. private static int counter = 0; 
  2.  
  3. public static void main(String[] args) { 
  4. //使用线程池 
  5. ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool(); 
  6. //提交2000个任务 
  7. for(int i = 0; i < 2000; i++) { 
  8. threadPool.submit(new Add()); 
  9. threadPool.shutdown(); 
  10. //打印最多使用线程数 
  11. System.out.println("largestPoolSize:" + threadPool.getLargestPoolSize()); 
  12. System.out.println(counter); 

输出结果如下:

  1. 第一次: 
  2. largestPoolSize:11 
  3. 1937 
  4. 第一次: 
  5. largestPoolSize:14 
  6. 1956 
  7. 第一次: 
  8. largestPoolSize:31 
  9. 1970 

可以看到每次都不一样,线程池之前有文章讲过,这个系列后面还会深入讲解。

关于 largestPoolSize, 注释说明了,记录线程池中最大的线程数。

  1.  
  2. private int largestPoolSize; 

面试官:看你代码中写了调用线程池的shutdown,那shutdown 和 shutdownNow 方法什么区别?

安琪拉:shutdown 是将线程池的状态设置为SHUTWDOWN状态,正在执行的任务会继续执行下去,没有被执行的则中断。而shutdownNow则是将线程池的状态设置为STOP,正在执行的任务则被停止,没被执行任务的则返回。

源码对比:

  1. //shutdown 
  2. public void shutdown() { 
  3.   final ReentrantLock mainLock = this.mainLock; 
  4.   mainLock.lock(); 
  5.   try { 
  6.     checkShutdownAccess(); 
  7.     //设置线程池状态为SHUTDOWN 
  8.     advanceRunState(SHUTDOWN); 
  9.     interruptIdleWorkers(); 
  10.     onShutdown(); // hook for ScheduledThreadPoolExecutor 
  11.   } finally { 
  12.     mainLock.unlock(); 
  13.   } 
  14.   tryTerminate(); 
  1. public List shutdownNow() { 
  2.   List tasks; 
  3.   final ReentrantLock mainLock = this.mainLock; 
  4.   mainLock.lock(); 
  5.   try { 
  6.     checkShutdownAccess(); 
  7.     //设置线程池状态为STOP 
  8.     advanceRunState(STOP); 
  9.     interruptWorkers(); 
  10.     //把队列剩余等待执行任务取出,返回 
  11.     tasks = drainQueue(); 
  12.   } finally { 
  13.     mainLock.unlock(); 
  14.   } 
  15.   tryTerminate(); 
  16.   return tasks; 

面试官:线程池有哪几种状态?

安琪拉:5种,注意这里说的是线程池的状态,不是线程的状态。下面是线程池的状态流转图:

本文是《并发》系列第一集,主要介绍了一些并发、并行、高并发的一些基础概念,以及并发安全问题的案例,下一集讲并发的风险与优势和CPU多级缓存,以及一些内存操作的指令,然后说Java内存模型。

完整大纲参考:

 

来源: 安琪拉的博客内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯