并发编程的挑战

学以致用,方得始终

并发编程的挑战

在学习并发编程首先需要明确一个问题就是:并发编程是让程序处理问题更快,让程序更大限度的并行执行,而不是开辟很多线程去执行任务。当然让并发编程作为使程序解决问题更加迅速的处理方案以及程序性能判断的时候,我们不得不考虑一下几点问题:

1. 线程上下文切换
2. 锁问题(死锁、活锁等)
3. 系统(硬件和软件)资源限制问题

首先为什么需要考虑线程上下文切换?以及什么是上下文切换的概念,什么是死锁,死锁会导致什么问题?如何根据系统资源为程序合理的分配线程数?这些都是我们需要考虑和研究的。

线程上下文切换

在单核处理器这种硬件支持下,一般会有时间片的概念,时间片就是一个线程可以占用CPU的时间,一般以ms为单位。关于为什么线程工作的时候会占用CPU,请脑补操作系统知识,此处不做赘述。
当多个线程同时执行的时候,其实在单核处理器下多个线程执行并不是齐头并进,而是分时交替获取CPU资源执行任务。而一个线程时间片执行结束后,线程处于就绪态,其他等待线程就会抢占CPU处理变为运行态

我们首先研究一下线程的声明周期,线程的声明周期主要包括6中状态,分别为新建就绪态可运行态运行态、、阻塞态消亡。那么六种状态之间以怎样的模式进行运转呢?我们可以看一下如下这张图:

在这里插入图片描述

  1. 新建状态:代码中使用new关键字,进行new出Thread的实例的过程
  2. 可运行状态:当在代码中new出一个Thread的实例后并不会直接执行,而是有一个中间状态,也成为就绪状态。调用start()方法之后,线程需要抢占CPU资源后变为运行状态。
  3. 运行态:当就绪线程并调度获取CPU资源后,便进入运行态,run方法中定义了线程需要执行的动作。当执行yield方法或时间片执行结束后会变为就绪态。
  4. 阻塞态:当线程在运行过程中遇到某些操作时,比如sleep和wait,会变成阻塞状态。阻塞线程需要通过notify和notifyAll对线程进行唤醒,进入就绪态。并不会立马执行run方法,而是等待机会获取CPU资源,获取线程资源。
  5. 终止:当线程执行结束或者代码终止线程时,线程会被销毁,释放资源。比如:stop方法。

当按照时间片算法进行线程轮询使用CPU的时候,需要的操作包括,保存上一个线程的运行时状态,等待下次从就绪态获取CPU后,恢复运行状态。这样的话如果频繁进行上下文切换的话,就会产生效率问题。首先我们考虑一个问题:多线程一定快速吗?看一下结果:

求和范围 并发(ms) 顺序(ms)
10 1ms 0ms
10000 1ms 1ms
10000000 16ms 16ms
1000000000000L 4689ms 5334ms

所以这个时候我们就需要考虑线程个数设置多少比较合适的问题:
多线程数量的设置一般要考虑任务的内部处理逻辑,一般分为IO密集型任务和计算密集型任务,但实际场景还需要考虑CPU,IO,内存等。

IO密集型任务主要处理IO操作,如网络通信,文件读写等,这种依赖于DMA,占用CPU资源比较少。这种情况如果没有使用多线程处理IO密集型任务,CPU就会产生资源浪费。那IO密集型任务的线程数一般等于(CPU内核数)/(1-阻塞系数),其中阻塞系数为(0.8-0.9)

计算密集型任务即应用中处理的时算法计算等,这种任务主要通过CPU完成,因此占用CPU资源较多。一般设置线程数为CPU内核数*2。Java可以使用一下方式设置。

Runtime.getRuntime().availableProcessors() * 2

混合型任务线程数量设置个数=(计算操作占用时间+IO操作占用时间)/计算操作占用时间。比如:混合型任务即包含计算操作也包含IO操作,假设整个任务处理时间为100ms,计算操作占用时间为20ms,IO操作占用时间为80ms,也就是说CPU只有大约五分之一在被占用,其他五分之四被浪费掉,这个时候需要启动的线程数=5。
言归正传,我们还回到多线程上下文切换,导致的性能和效率问题上来。首先我们如何确认上下文切换次数呢?
linux环境下可以使用vmstat测量上下文切换的次数。查看CS字段既可以看出上线文切换次数

image.png

如上多线程切换次数大概在600~700次之间。
image.png

那么如何减少线程的切换次数呢?

减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。 ·无锁并发编程。多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一 些办法来避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。

CAS算法。Java的Atomic包使用CAS算法来更新数据,而不需要加锁。 ·使用最少线程。避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态。

协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。

简单的做一个实战演练:

减少线上WAITING线程,减少上下文切换次数。首先使用java堆栈信息分析命令jstack查看某一端口对应的进行的线程的状态。然后统计线程的状态的个数:

grep java.lang.Thread.State dump文件 | awk '{print $2$3$4$5}' | sort | uniq -c

然后分析对应状态为WAITING的线程作用,并减少线程个数。

锁问题

死锁:多个进程由于竞争资源,而导致程序无法推进,需要外部环境破坏非安全条件。

如何获取死锁的状态:死锁的状态为BLOCKED状态,我们可以使用jstack获取堆栈信息,然后根据堆栈信息进行分析BLOCKED状态的线程信息,判断是否产生DeadLock问题。

如何避免死锁呢?

  1. 避免一个线程同时获取多个锁。
  2. 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
  3. 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。 4. 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

活锁:不同的进程在相同时间做相同的动作,就像两个人过马路,双方同时给对方让路。进程在执行,但不会往下执行。

饥饿:根据系统资源分配策略可能会导致一些进程永远得不到服务。

软硬件资源

软硬件资源,比如带宽,内存等对多线程产生的影响。可以使用分布式场景下处理多线程资源的问题。比如使用hadoop等。

参考

《Java多线程编程艺术》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355

推荐阅读更多精彩内容