//阅读学习《Java并发编程的艺术》笔记,第一章
目录
序、进程与线程
1、定义:
- 独立运行的程序叫做进程,进程里面的运算单元都是线程组成的
- 进程从规模上大于线程,进程包含线程,一个进程由一到多个线程组成
2、代码理解:
- 主线程拷贝主方法压入栈中
- 在主方法中启动了两个线程t1、t2,之后相互独立互不干扰
- start()表明进入就绪状态,何时执行取决于何时被CPU选中
3、线程切换及原因:
- 每一个核同一时间只能做一件事情,所以想要执行任务需要获取时间片,切换执行
- 等待时间片时间越长,优先级越高
- windows一般是变长时间片,Linux一般是定长时间片
- 上下文切换:上次执行到哪里,记录下来,下次还从这里开始。所以任务从保存到再加载的过程就是一次上下文切换。
- 线程切换需要将近1ms,是有时间消耗的,所以多线程不一定比单线程快
- 如果在单核CPU且没有CPU浪费的情况下,单线程比多线程快,因为线程切换有时间消耗
- 现代电脑双核或四核,使用多线程相当于把其他核也利用起来,所以多线程会比单线程快
4、多线程的使用场景:
1、实际业务需要
比如Windows操作系统,同时打开QQ、微信、腾讯会议需要在这三个软件之间来回切换,像这种需要同时进行的操作就需要使用多线程。
2、CPU有严重浪费的时候
使用多线程会提高CPU的利用率
实际场景:网络爬虫,数据库操作
5、主要看CPU浪费占比
假设每个任务CPU空闲10ms,已知多线程切换有时间消耗。
Java处理需要3000ms,CPU浪费等待了10ms,占比太小,使用多线程并不合适。
不一定CPU浪费的时间多就用多线程,得看CPU浪费占总时间的比例是多少,占比大用多线程才合适。
不合适用多线程实际场景:图像处理、视频处理
一、并发编程的挑战
Lmbench3性能分析工具,面试加分
1、如何减少上下文切换:
减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。
无锁并发编程。多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据。
CAS算法。Java的Atomic包使用CAS算法来更新数据,而不需要加锁。
使用最少线程。避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这样会造成大量线程都处于等待状态。
协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。
2、减少上下文切换实战
dump:查看当前快照信息
指令:sudo -u admin /opt/ifeve/java/bin/jstack 31177 > /home/tengfei.fangtf/dump17
意为:sudo是linux中的命令,用管理员身份使用jdk的/opt/ifeve/java/bin/jstack指令把进程pid为31177的快照信息存到该路径下,命名为dump17
指令:grep java.lang.Thread.State dump17 | awk '{print $2$3$4$5}' | sort | uniq -c
意为:grep筛选按照这种格式输出,unip -c表示统计
如何根据进程id查看线程信息?
答案就是上面的两条指令。
3、死锁
- synchronized上锁,执行时加锁,执行完后将其释放,使用引用类型上锁,不能用基本类型
- 为何导致死锁:上锁后互相等待对方资源
避免死锁的几个常见方法:
1、避免一个线程同时获取多个锁。
2、避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
3、尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
4、对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
第一章的笔记end!