java并发编程的艺术读书笔记(一)

故事扮演 提交于 2020-02-27 08:12:58

并发编程的目的是为了程序运行的更快。

1.上下文切换:

时间片:cpu分配给各个线程的时间。

单核处理器也支持多线程执行代码。

cpu通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换。

多线程不一定快,因为线程有创建和上下文切换的开销。

使用Lmbench可以测试上下文切换的时长(什么时候需要看这个参数呢)。

使用vmstat可以测量上下文切换的次数。比如:执行vmstat 1,再看cs的值,cs表示上下文切换的次数,这个值表示每一秒钟上下文切换的次数。(什么时候需要用到这个命令呢?)

减少上下文切换的方法:

1.无锁并发编程。多线程竞争锁时,会引发上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,比如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。

2.CAS算法。eg:java的atomic包使用CAS算法来更新数据,而不需要加锁。

3.使用最少线程。

4.使用协程。协程:在单线程里实现多线程的调度,并在单线程里维持多个线程间的切换。

减少上下文切换实战:

通过减少线上大量WAITING的线程,来减少上下文切换的次数。

第一步:用jstack命令dump线程信息,看pid为3117的进程在做什么

sudo -u admin jstack 3117>/temp

第2步:统计所有线程分别处于什么状态

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

本来应该截图的,不太方便直接把命令和结果赋值粘贴过来:

[tengfei.fangtf@ifeve ~]$ grep java.lang.Thread.State dump17 | awk '{print $2$3$4$5}'
    | sort | uniq -c
39 RUNNABLE
21 TIMED_WAITING(onobjectmonitor)
6 TIMED_WAITING(parking)
51 TIMED_WAITING(sleeping)
305 WAITING(onobjectmonitor)
3 WAITING(parking)

第三步:打开dump文件查看处于WAITING(onobjectmonitor)的线程在做什么,比如这本书的例子中,基本都是JBOSS的工作线程在await,说明JBOSS线程池里线程池里接受的任务太少;减少JBOSS的工作线程数,找到JBOSS的线程池配置信息,将maxThreads值调小。重启JBOSS,再dump线程信息,然后统计WAITING(onobjectmonitor)的线程,发现减少了很多。=====》因为每一次从WAITING到RUNNABLE都会进行一次上下文的切换。

=====》拓展:

什么使用需要用到jstack命令dump线程信息?

我印象很深的一次就是一个lisener的项目,上线一段时间后,某个队列突然都阻塞了,消息不消费了,当时在listener admin控制台把阻塞的线程停用再启用,阻塞的消息很快都消费了,过了一段时间,这个项目的对应的另一个队列阻塞,停用再启用之后阻塞的消息也都消费了,但是有一条unacked,当时用jstack命令dump了线程信息,然后在本地启动项目,在dump线程信息,异常的线程信息和正常的线程信息对比,排查问题。====》这个是因为esl连接有问题,是怎么发现是esl的连接有问题的。想不起来了,这个记得自己研究下,做一下记录。

死锁的时候需要用这个命令dump线程信息。

2.死锁

一旦出现死锁,业务是可以感知的,因为不能继续提供服务了,只能通过dump线程查看到底是哪个线程出现了问题。

===》工作中是否遇到过线上环境死锁?我听过同事遇到过,向他请教下他是怎么知道的,怎么排查的,怎么解决问题的,做好笔记。

避免死锁的方法:

1.避免一个线程同时获取多个锁。

2.避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。

3.尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。====》sornarlint优化的时候,遇到一个锁的优化,后来因为优化会有潜在风险,没有优化,看看那个点,对比总结下。

4.对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

3.资源限制的挑战

资源限制:在进行并发编程时,程序的执行速度受限于计算机硬件资源或软件资源。

硬件资源限制有带宽的上传/下载速度、硬盘读写速度和CPU的处理速度。

软件资源限制有数据库的连接数和socket连接数等。

资源限制引发的问题:并发执行的代码受资源限制串行执行,速度会更慢,增加了上下文切换和资源调度的时间。

如果解决资源限制的问题:对于硬件资源限制,可以考虑使用集群并行执行程序。对于软件资源限制,可以考虑使用资源池将资源复用。总之,根据不同的资源限制调整程序的并发数。

java并发机制的底层实现原理:

java代码在编译后会变成java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,java中所使用的并发机制依赖于JVM的实现和CPU的指令。 1.volatile volatile是轻量级的synchronized,它在多处理开发中保证了共享变量的“可见性”。 volatile使用恰当的话,比synchronized使用和执行成本更低,它不会引起线程上下文的切换和调度。

先了解几个CPU术语:

未完待续。。。。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!