没有合适的资源?快使用搜索试试~ 我知道了~
面试宝典-技术栈整理-致敬老王同志
需积分: 5 0 下载量 39 浏览量
2023-08-15
16:45:49
上传
评论
收藏 25.84MB DOCX 举报
温馨提示
试读
215页
面试宝典-技术栈整理-致敬老王同志
资源推荐
资源详情
资源评论
1
技术栈
1、 java
1.1 多线程,并发
1、线程池中提交一个任务的流程是怎么样的?
1、在使用 excute()方法提交一个 runnable 对象时
2、会判断当前线程池中线程的数量是否小于 corepoolsize
3、如果小于,则创建新线程并执行 runnable
4、如果大于等于则尝试将线程加入到 workQuque 中
5、如果 workQueue 没满则正常入队,等待被执行
6、如果 workQueue 满了,则入队失败,那么会尝试增加线程
7、判断当前线程池中的线程数是否小于 maxinumPoolSize
8、如果小于,则创建新线程并执行任务
9、如果大于等于,则执行拒绝策略,拒绝此 runnable
2、线程池中有几种状态,是如何变化的?
线程池中的五种状态:
Running:会接收新任务,并处理队列中的任务
shutdown:不会接收新任务,会处理队列中的任务,当队列中的人物处理完后会关闭所有线程,
当调用 shutdown()方法时
stop:不会接收新任务,也不会处理队列中的任务,同时会直接停掉所有的线程:当调用
shutdownNow()方法时
tidying:所有的线程都停止后,线程池的状态就会转化为 tidying,一旦达到这种状态就会调
用线程池的 teriminated()
teriminated:teriminated()执行完后就会转化为 terimitated 状态
这五种状态不能任意转化,只会有一下几种状况
2
转变前
转变后
转变条件
running
shutdown
手动调用线程池的 shutdown 或者线程池的对象 GC 时 finalize()从而调用
shutdown 方法
running
stop
手动调用 shutdownNow 方法
shutdow
n
stop
手动调用了 shutdown 方法,紧接着调用 shutdownNow 方法
shutdow
n
tidying
线程池中所有线程都停止后自动触发
stop
tidying
线程池中所有的线程都停止后自动触发
tidying
teriminate
d
线程池自动调用 terminated 方法后触发
3、如何安全的停止一个线程
thread 类中有 2 个方法
start():开启一个线程
stop():停止一个线程
stop 方法不建议使用,后期可能删除,因为 stop 太过粗暴,会直接停掉线程,这样会造成一系
列问题,比如线程执行到哪一步了,该释放的锁是否释放都存在问题。注意:stop 会释放
synchnorizd 锁但是不会释放 reentantlock 锁,通常建议使用终端停止线程。
4、线程池核心线程数,最大线程数如何设置
1、线程池中有两个重要参数:
1、corePoolSize:核心线程数,表示线程池中的常驻线程个数
2、maximumPoolSize:最大线程数,表示线程池中能开辟的最大线程数
2、这两个参数如何设置
对线程池执行的任务分三种情况
1、cpu 密集型任务,例如找到 1-10000 中的素数
cpu 密集型任务的特点是线程执行时会一直利用 cpu,这种情况要尽量避免线程的上下文切
换,比如我的电脑只有一个 cpu,如果两个线程在同时执行找素数的任务,那么这个线程就需要
额外的进行线程的上下文切换,从而达到线程的并行效果,此时执行这两个任务的时间为:任务
执行时间 * 2 + 线程上下文切换时间。而如果只有一个线程,这个线程来执行两个任务,那么
3
时间为:任务执行时间 * 2。所以对于 CPU 密集型的任务线程数最好就等于 cpu 的核心数,可以
通过以下 api 拿到电脑的核心数:Runtime.getRuntime().availableProcessors();只不过,为
了应对现成执行过程中发生缺页中断或其他异常导致线程阻塞的请求,我们可以额外多设置一个
线程,这样当某个线程不需要 cpu 时,可以用来替补线程继续利用 cpu,所以对于 cpu 密集型任
务,我们可以设置线程数为:cpu 核心数 + 1
2、Io 密集型任务,比如文件 Io,网络 Io
线程在执行任务时大部分时间阻塞在 IO 上,加入现在有 10 个 cpu,如果我们只设置 10 的
线程来执行 IO 任务,那么如果这 10 个线程都阻塞在了 IO 上,那么 10 个 cpu 就没活干了,所以
对于 IO 密集型的任务设置核心线程数为:2*CPU 核心数。不过即使设置了 2 倍的 cpu 核心数,
也可能都阻塞到 IO 读写上,也不一定是最优的,所以可以再增加线程数去尽可能的利用 cpu,
通常 IO 执行的时间越长,阻塞的线程数就会越多,但是也不是设置越多的线程数是最好的,通
常我们可以通过以下公式去计算:
线程数 = 核心线程数 * (1 + 线程等待时间/线程运行总时间)
线程等待时间:线程等待使用 cpu 的时间,比如阻塞在了 IO
线程运行总时间:指线程执行完某个任务的总时间
我们可以使用 jvisualvm 抽样来估算这两个时间:
以上只是理论上设置的线程数,实际情况会比较复杂,比如一个应用可能有多个线程池,除了线
程池中的线程可能还有很多其他线程或者除开这个应用还有其他应用,,所以实际工作中确定线
程数最好的方法还是压测
3、混合型任务
5、如何理解 java 并发的可见性,原子性,有序性
1、可见性
java 并发中的可见性是多线程在访问共享变量时,对变量的更改能被其他线程及时感知,
即一个线程修改变量时,其他线程能立刻看到结果。
4
当现成 A 读取变量 I 的值时会混存一份值到 cpu1 的高速缓存中,如果线程 A 修改 i 且没有回填
到内存中,线程 B 也读取 i 的值,那么读取的结果就不是 A 修改后的值,就会出现可见性的问题。
在 java 中 volatile 关键字是保证变量可见性,在读取变量时直接从内存中读取,再修改变量时
就会修改高速缓存的值和内存中的值,从而保持变量的一致性。
2、原子性
java 并发原子性是在多线程并发的情况下,一段代码或者操作要么全部执行成功,要么全
部失败,不存在一段代码执行一般被其他线程打断或者干扰的情况。换句话说,就是对同一个变
量的多个操作能够像原子操作一样,保证多线程环境下的数据一致性,避免出现数据竞争和脏数
的问题。由于内存,cpu,IO(网络,磁盘)之间的差距,为了充分利用 cpu,当线程执行 IO 操
作时,线程会让出 CPU,使得 CPU 去执行其他线程的指令,并且本身来说,为了达到线程并发执
行的效果,CPU 也会按照固定的时间片来切换执行同步的线程。但我们执行 I++代码时,底层进
行对应的以下三条指令:
1、从内存中读取 i 的值
2、对 i 进行+1
3、写会 i 的值到 cpu 的高速缓存
但是有可能线程 A 执行第一条指令后就发生了线程切换,线程 A 处于暂停状态,此时线程 B
也进行以上操作,并且把三步都执行完了,那么线程 B 得到值就是 2。然后先层 A 继续执行,最
终线程 A 得到的值也是 2,理论上应该是 3,这就是原子性问题。
5
java 中我们需要使用各种锁来保证原子性。
3、有序性
java 并发的有序性指多个线程执行的指令和操作按照开发者编写的既定的顺序或者预定的
顺序进行执行。多线程并发时可能会发生指令重排,导致程序的顺序与预期不一致,从而出现数
据竞争和线程安全的问题。编译器有时为了进行编译优化会进行指令重排序,比如:new Person();
这个代码会分成三步:
1、申请内存
2、返回内存地址
3、在内存空间初始化 Person 对象相关的内容
所以对于我们的单例模式实现:
就算用了 DCL 也会出问题,比如线程 A 拿到锁后,在 new Person()时,第二步就返回内存地址
并赋予给了 instance 变量,此时线程 B 过来拿执行 getInstance()直接就判断 Instance 不为空,
但是 instance 对于的对象其实还没有初始化的,里面的成员变量可能还是为 null。我们可以通
过锁机制或者 volatile 来保证有序性。
剩余214页未读,继续阅读
资源评论
pangjchao
- 粉丝: 4
- 资源: 3
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功