1、为何要使用多线程?
【使计算机全部资源在执行任务的时候可以所有利用上,以提高计算机资源利用率的方式来提高系统执行效率】
CPU的单核运行速度因为硬件技术问题已经遇到瓶颈,而概念性的“光脑”貌似离咱们还很遥远,如今的计算机性能提高方向是向多核发展。多核同时工做,协同完成任务。你们熟知的神威·太湖之光超级计算机总共使用了40960颗处理器,总计拥有10649600颗核心、1.31PB内存。即便是目前市场上的主流家用电脑也通常达到四核心八线程的配置标准。那么对于这些多核的CPU,在开发软件的时候就不得不考虑如何充分利用上每个核的性能,以致于使系统运行的效率更高。
2、CPU是执行的是线程任务仍是进程任务?
【CPU执行的是线程中定义的任务】
进程是对内存资源的抽象,线程是对执行任务的抽象。CPU执行的是线程任务,和进程没有任何关系。因此,CPU中的核在任意时间点只能执行某一个线程的任务,具体执行哪一个线程就要看操做系统的任务调度策略。在单核多线程任务中,操做系统会把CPU资源按照时间片划分,根据线程的优先级选择线程进行执行任务。
3、程序中线程的数量控制在核数的1~2倍对吗?
【不对!】 html
左图为工做时win10 四核八线程 线程数: 2094。右图为闲置centos7 单核 线程数 :127 。线程数量远远超过CPU核心数量的上百倍。centos
因此在开发程序过程当中,若是不是线程开启机制错误,就不会产生成上万级别的线程致使线程切换浪费资源,而几百个线程切换对CPU来讲还不至于产生过多的资源消耗。
线程开启机制错误例子:socket每接收一个请求便建立一个线程执行任务。这种状况下,很容易的便能开启上千上万个线程(在工做中遇到过)。
4、线程频繁切换会耗费资源?
【消耗资源确定会,可是消耗的资源通常状况下不必重视,当须要去重视的时候你就不会在看本文了】
线程消耗一定会耗费计算机资源,影响系统的执行效率。可是这种级别的资源浪费还不必引发关注去考虑优化,随便优化一个SQL查询就远远比优化线程切换性能提高的多。
测试:
计算任务:计算1亿次 f(i)=(i * 10000.56) / 200 (i从1循环到10000) 每组数据测试4次。
电脑配置: 四核八核心CPU 8G内存 win10系统(测试过程当中运行的有其它程序,但整个过程当中没有新的应用程序开启或者关闭。测试先后计算机进程数102左右,线程数210左右)
数据以下:单位s
1线程执行10000 * 10000次相同任务运算时间:0.043584183000000006
1线程执行10000 * 10000次相同任务运算时间:0.03411422
1线程执行10000 * 10000次相同任务运算时间:0.033755275
1线程执行10000 * 10000次相同任务运算时间:0.037857329
10线程执行10000 * 1000次相同任务运算时间:0.020971566
10线程执行10000 * 1000次相同任务运算时间:0.020400791
10线程执行10000 * 1000次相同任务运算时间:0.043275417000000004
10线程执行10000 * 1000次相同任务运算时间:0.020918537
50线程执行10000 * 200次相同任务运算时间:0.041526313
50线程执行10000 * 200次相同任务运算时间:0.028923265
50线程执行10000 * 200次相同任务运算时间:0.020633701000000003
50线程执行10000 * 200次相同任务运算时间:0.01057820000000002
100线程执行10000 * 100次相同任务运算时间:0.034126764000000004
100线程执行10000 * 100次相同任务运算时间:0.036614853
100线程执行10000 * 100次相同任务运算时间:0.060594536000000004
100线程执行10000 * 100次相同任务运算时间:0.046860865
500线程执行10000 * 20次相同任务运算时间:0.054617363
500线程执行10000 * 20次相同任务运算时间:0.090330437
500线程执行10000 * 20次相同任务运算时间:0.060385270000000005
500线程执行10000 * 20次相同任务运算时间:0.06421362700000001
1000线程执行10000 * 10次相同任务运算时间:0.101977442
1000线程执行10000 * 10次相同任务运算时间:0.09040313700000001
1000线程执行10000 * 10次相同任务运算时间:0.094736125
1000线程执行10000 * 10次相同任务运算时间:0.09127384000000001
2000线程执行10000 * 5次相同任务运算时间:0.16429143000000002
2000线程执行10000 * 5次相同任务运算时间:0.18807325200000002
2000线程执行10000 * 5次相同任务运算时间:0.16652977000000002
2000线程执行10000 * 5次相同任务运算时间:0.18108197
5000线程执行10000 * 2次相同任务运算时间:0.44204793600000003
5000线程执行10000 * 2次相同任务运算时间:0.484968116
5000线程执行10000 * 2次相同任务运算时间:0.405066727
5000线程执行10000 * 2次相同任务运算时间:0.42432967400000005
10000线程执行10000 * 1次相同任务运算时间:1.453686674
10000线程执行10000 * 1次相同任务运算时间:1.307516071
10000线程执行10000 * 1次相同任务运算时间:1.5121169970000001
10000线程执行10000 * 1次相同任务运算时间:1.332141795
由数据中能够看出,在程序开启1-50个线程时,执行时间在降低,10-1000个线程以内,执行时间都在同一个量级,超过一千线程以后,时间提高一个量级。所以,粗略来看 1000个如下线程切换并不会浪费大量系统资源。在程序中若是线程开启机制正确,同时使用到线程池,那么系统优化瓶颈就不会在线程切换的问题上。不必在这个角度考虑系统优化的问题。
测试代码以下:多线程
//scala2.12.12 jdk1.8 def showNCPUTime(): Unit = { //测试过程当中调整threadNum,inner 这两个参数,同时保证二者之积不变 inner * theradNum =10000
val threadNum = 2000 val inner = 5 //固定不变 val top = 10000 val state = new CountDownLatch(threadNum) var threads = new Array[Thread](threadNum) for (time <- (0 until threadNum)) { val thread = new Thread(new Runnable { override def run(): Unit = { for (i <- (1 to top)) { for (j <- (1 to inner)) { //i 每次都是从1 到 1000000 val temp = (i * 105300.56) / 200 } } state.countDown() } }) threads(time) = thread } var startTime = System.nanoTime for (time <- (0 until threadNum)) { threads(time).start() } state.await() val endTime = System.nanoTime println(threadNum + "线程执行" + top + " * " + inner + "次相同任务运算时间:" + (endTime - startTime) * 0.000000001) }
5、使用多线程的难点在哪里?
多线程的难点在于共享数据读写顺序的问题,保证多个线程对同一数据的操做不会产生混乱。
程序中流动的都是数据,程序影响的也都是数据。在多个线程同时访问共享数据的时候,因为线程读取/写入的时机不对而致使数据出错,进而影响业务。socket
下面的问题涉及到操做系统底层知识,列出来只是为了引发读者的思考,再也不回答,以避免误人误己。
6、对于多核CPU,线程任务是如何分配到每一个核上面的?
7、单核CPU任务调度策略。在多个线程中,操做系统是如何选取其中某个线程分配给CPU执行的?选取规则是什么?
8、线程切换耗费资源,那么都耗费在什么地方?挂起一个线程的时候操做系统都进行了哪些操做?
9、操做系统开启一个新线程须要执行哪些步骤?计算机可以开启的最大线程数是多少?JVM可以开启的最大线程数是多少?他们和内存的大小有什么关系?ide
=============================================post
原文连接:多线程(二)使用多线程的准备知识 转载请注明出处!性能
=============================================测试
-----end优化