多线程并发的使用、学习与测试

  使用

  先说说多线程的使用。多线程本身是与我们开发的项目密不可分的,我们只要提供了接口,那么他就可能被多个线程同时调用,就会产生并发问题,因此开发者在实际开发中对多线程的理解至关重要。当然,这属于最基本的认识。

  就这一方面而言,对于开发者及学过并发的学员,平时开发中需要掌握的主要包括:

  1.先说涉及最多的。看到static修饰的变量时,能想到涉及到多线程资源共享。如果是可变的,需要注意变化中的线程安全;如果是不可变的,需要知道如何保证其不可变,而不是简单的放在那,当前代码没有修改他就认为他是不变的。

  2.看到final、单例等定义时,能分析出是否是线程安全的。

  3.在看到集合、Map等结果时候时,知道该选什么类更适合,以及什么时候适合使用并发类,什么时候适合使用普通的类,这里本质上有对线程封闭的理解。

  4.在遇到SimpleDateFormat等线程不安全的类时,能知道相关的并发风险点

  5.在需要完成一些大任务时,知道如何借助线程池等进行提速,以及借助AQS相关组件进行一些线程的调度

  6.知道常用的线程安全手段,能根据场景去分析是否需要加锁来保证线程安全。

  说了这么多,相信很多人已经能感受到并发在日常开发中的存在,也能对并发多一些认识。虽然你可能很难用上并发一些手段,但你需要知道你看到的代码是否有问题,并发问题更多的存在于一些细节的处理中。这也是很多学员问我为什么不出一门关于并发实战性质的课程、而是选择根据在知识点的讲解过程中介绍使用他们的一些场景的愿意。同时,由于并发的知识点多而繁杂,单独一门课程的几个场景很难覆盖整个并发知识体系,这样直接会导致许多人学完了并发却还是和之前一样,只是巩固了一遍知识点,别人问起来心里依旧很虚。而且,如果为了覆盖知识点去刻意的在某些场景中使用并发的某些知识点,反而可能会造成很多误解,效果并不一定理想。

  继续谈多线程的使用。之前介绍的是我们不得不处理的多线程,接下来介绍主动创建的多线程的使用,即我们在代码里主动使用多线程去处理一些业务。

  1.提速,充分利用CPU:这个理解起来应该比较容易,同一个任务,多个线程同时处理,让很多处理并行,达到更快完成的目的。这里介绍的一个场景,之前项目做大发布,要清洗历史数据(比如要根据id取出某一行,并计算某个值填进去),由于数据量很大,单线程清洗可能要1个小时左右,为了能尽快完成,不影响发布的时间,因此我们把单线程改为10个线程并行,测试发现10个线程还是有些慢,后来调整为20个线程同时处理,这样最终在3min左右完成。

  2.降速,协调资源的使用:刚说完提速,这里又说降速,许多人可能会很奇怪。这里举具体例子来说明一下,比如项目里要发短信,目前有第三方的限制是并发量最多10条,而每天高峰期时段同一时刻需要发送的短信量可能远高于10条,这时怎么办呢?就可以在发短信时引入线程池及多线程池处理,通过semaphore等控制同时发短信的线程不超过10,这样就起到了降速的作用。

  3.异步处理,解耦。通常我们在做一个业务实现时,都有主流程和次流程之分,比如我们用户下单时,同时还要完成记录核心日志(核心的日志可能要记录的数据库中)以及通知用户下单完成等非核心业务,这些非核心的业务在处理时,有时可能会很耗时,出任何错还不能让主流程失败,出错了还需要重试慢慢完成,这种的就可以开启新的线程去处理,异步解耦,让主流程快速完成并返回。当然,也不能无限制的开启新线程,放在线程池里控制更好。

  许多人不知道如何使用多线程,希望这几点总结能让加深你的理解。关于多线程的使用,在什么场景该使用什么场景不该使用不是背下来的,而是需要结合实际场景分析,是否需要进行提速、降速、异步处理等,如此才能在工作中较好的使用多线程。

  学习

  之前在面试中并发类问题的准备和学习大致介绍过,这里就不做过多的讲解,做个简单的总结:

  

  还是课程里这张图,这张图不是简单的覆盖了并发的知识点,而是希望你能将这幅图印在脑子里。当你向别人讲述并发时,能先从整体描述并发的几个大方面,然后能挨个大方面进行细化。这也是你学习并发比较好的方法,脑海中有这个图,你就可以迅速的把知识点过一遍,哪个知识点模糊了你可以去补充一下就可以了,而不是每次需要学习并发时都是从头来一遍,而且每次看完都感觉还差点啥。

  这个方法呢,也特别适合在面试中使用。面试官在让你说说对并发的了解时,你能先整体概括再局部细化,会让你在这个环节大大加分。不少学员已经从中受益,希望这个也能帮助到你。当然,这种先整体概括再局部细化的方式,也适合大家学习其他方面的知识,会让你的记忆更深刻,后续巩固也容易很多。

  测试

  说了并发的使用与学习,之后就是验证了,也属于并发的测试。并发的测试通常可以选择通过接口和方法两个方向去验证,可以根据不同需要进行选择。

  先说根据接口测试。这种的通常要借助工具,Postman、JMeter、Apache Bench(AB)等都是不错的选择,其中JMeter、Apache Bench(AB)更适合测试人员来使用,Postman更适合开发人员来使用。

  再说说根据方法测试。方法的测试更适合写代码去测试,这里给出一个模板:

  public class ConcurrencyTest {

  // 请求的总数

  public static int clientTotal = 5000;

  // 同时并发执行的线程数

  public static int threadTotal = 200;

  public static void main(String[] args) throws Exception {

  ExecutorService executorService = Executors.newCachedThreadPool();

  final Semaphoresemaphore = new Semaphore(threadTotal);

  final CountDownLatchcountDownLatch = new CountDownLatch(clientTotal);

  for (int i = 0; i clientTotal ; i++) {

  executorService.execute(() - {

  try {

  semaphore.acquire();

  testMethod();

  semaphore.release();

  } catch (Exception e) {

  log.error(exception, e);

  }

  countDownLatch.countDown();

  });

  }

  countDownLatch.await();

  executorService.shutdown();

  // 所有线程执行完,之后才能执行的部分

  }

  private static void testMethod() {

  // 待验证的方法

  }

  }

  testMethod这个方法替换为要测试的方法就可以了。如果不需要在所有线程执行完执行某些代码,可以去掉CountDownLatch的使用;如果不需要控制同一时间同时并行的线程数,可以去掉Semaphore的使用。

  这里顺便补充一个技巧,有时为了让测试结果更明显一些,testMethod方法里可以考虑通过Thread.sleep方法让测试方法执行的慢一些,让并发测试的结果更显著。

  另外希望一定注意的是,在实际项目中,尤其是分布式系统并发场景,核心点要有日志记录核心变量的值。但一定不要使用System.out去输出日志,而我们通常讨论的slf4j、logback等,则是推荐使用的,因为他们会包含我们分析时能用到的:线程名称、代码行、及输出日志的时间等,System.out不光是没这些重要信息,而且在输出时使用了synchronized,这直接导致输出日志那里会出现线程阻塞。更

  实际项目中,尤其是在分布式系统里,很多问题的分析,我们都要依靠项目运行过程中输出的日志。线程名称、代码行、输出日志的时间、相关的变量值这几项又是分析过程中最关键的,希望大家能引起重视。

  

?

原文地址:https://www.cnblogs.com/qfdsj/p/9506066.html

时间: 2024-10-19 05:04:04

多线程并发的使用、学习与测试的相关文章

linux网络编程学习笔记之四 -----多线程并发服务端

相对于使用进程实现并发,用线程的实现更加轻量.每个线程都是独立的逻辑流.线程是CPU上独立调度运行的最小单位,而进程是资源分配的单位.当然这是在微内核的操作系统上说的,简言之这种操作系统的内核是只提供最基本的OS服务,更多参看点击打开链接 每个线程有它自己的线程上下文,包括一个唯一的线程ID(linux上实现为unsigned long),栈,栈指针,程序计数器.通用目的寄存器和条件码,还有自己的信号掩码和优先级.同一个进程里的线程共享这个进程的整个虚拟地址空间,包括可执行的程序文本.程序的全局

Spring-batch学习总结(2)—Job,Flow创建及应用,多线程并发,决策器,监听器,参数

一.Job的创建及其应用1.Job flow的介绍:(1)状态机:例完成step1,是否继续完成step2,step3,我们就需要通过Job flow来控制(2)进行演示:使用next()方法来达到顺序执行step1,step2...的目的,再使用on(),to(),from()方法达到与next()方法同样的目的,再展示fail()方法和stopAndRestart()方法:例1:创建JobFlowDemoOne,以及三个Step使用next()让其顺序执行JobFlowDemOne: pac

多线程并发编程

前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们来说极其重要,下面跟我一起开启本次的学习之旅吧. 正文 线程与进程 1 线程:进程中负责程序执行的执行单元线程本身依靠程序进行运行线程是程序中的顺序控制流,只能使用分配给程序的资源和环境 2 进程:执行中的程序一个进程至少包含一个线程 3 单线程:程序中只存在一个线程,实际上主方法就是一个主线程 4 多线程:在一个程序中运行多个任务目的是更好地使用CPU资源 线程的实现 继承Thread类 在j

java多线程并发概览

一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. "同时"执行是人的感觉,在线程之间实际上轮换执行. 二.Java中的线程 在J

Java多线程(全)学习笔记(下)

七.Callable和Future接口 C#可以把任意方法包装成线程执行体,包括那些有返回值的方法.Java也从jdk1.5开始,加入了Callable接口用来扩展Runnable接口的功能,Callable接口提供一个call()来增强Runnable的run().因为call()可以有返回值,可以声明抛出异常. 但是Callable是新增的接口 并没有继承Runnable接口,那么肯定不能作为Runnable target来直接作为Thread构造方法的参数.必须由一个中间的类来包装Call

C# 防止同时调用=========使用读写锁三行代码简单解决多线程并发的问题

http://www.jb51.net/article/99718.htm 本文主要介绍了C#使用读写锁三行代码简单解决多线程并发写入文件时提示"文件正在由另一进程使用,因此该进程无法访问此文件"的问题.需要的朋友可以参考借鉴 在开发程序的过程中,难免少不了写入错误日志这个关键功能.实现这个功能,可以选择使用第三方日志插件,也可以选择使用数据库,还可以自己写个简单的方法把错误信息记录到日志文件. 选择最后一种方法实现的时候,若对文件操作与线程同步不熟悉,问题就有可能出现了,因为同一个文

【JavaScript】吃饱了撑的系列之JavaScript模拟多线程并发

前言 最近,明学是一个火热的话题,而我,却也想当那么一回明学家,那就是,把JavaScript和多线程并发这两个八竿子打不找的东西,给硬凑了起来,还写了一个并发库concurrent-thread-js.尴尬的是,当我发现其中的不合理之处,即这个东东的应用场景究竟是什么时,我发现我已经把代码写完了. ??注意! 本文中的线程指的都是用JS异步函数模拟的“假线程”,不是真正意义上的多线程,请不要误解?? github地址 https://github.com/penghuwan/concurren

Java并发编程(03):多线程并发访问,同步控制

本文源码:GitHub·点这里 || GitEE·点这里 一.并发问题 多线程学习的时候,要面对的第一个复杂问题就是,并发模式下变量的访问,如果不理清楚内在流程和原因,经常会出现这样一个问题:线程处理后的变量值不是自己想要的,可能还会一脸懵的说:这不合逻辑吧? 1.成员变量访问 多个线程访问类的成员变量,可能会带来各种问题. public class AccessVar01 { public static void main(String[] args) { Var01Test var01Tes

Python多线程(threading)学习总结

注:此文除了例子和使用心得是自己写的,很多都是Python核心编程中的原文.原文文风应该能看出来,就不每个地方单独表明出处了. 线程(有时被称为轻量级进程)跟进程有些相似,不同的是,所有的线程运行在同一个进程中,共享相同的运行环境.它们可以想像成是在主进程或"主线程"中并行运行的"迷你进程". 线程有开始,顺序执行和结束三部分.它有一个自己的指令指针,记录自己运行到什么地方.线程的运行可能被抢占(中断),或暂时的被挂起(也叫睡眠),让其它的线程运行,这叫做让步.一个