赞
踩
目录
8 线程池用过吗?ThreadPoolExecutor谈谈你的理解?
上半部分:
大厂高频面试题复习JAVA学习笔记-JUC多线程及高并发(上)-CSDN博客
synchronized和lock的区别
- synchronized是jvm的关键字,lock是一个接口
- monitorenter(底层是通过monitor对象来完成,其史wait/notify等方法也依赖于monitor对象只有在同步块或方法中才能源wait/notify等方法
- Lock是具体类(java.util.concurrent.locks.Lock)是api层面的锁
- 锁释放
- synchronized 不需要用户去手动释放锁,当synchronized代码执行完后系统会自动让线程释放对锁的占用
- ReentrantLock则需要用户去手动释放锁若没有主动释放锁,就有可能导致出现死锁现象。需要lock()和unlock()方法配合try/finally语句块来完成。
- 等待是否可中断
- synchronized不可中断,除非抛出异常或者正常运行完成
- ReentrantLock 可中断,1.设置超时方法 tryLock(long timeout, Timeunit unit)
- lockInterruptibly()放代码块中,调用interrupt()方法可中断
- 加锁是否公平
- synchronized非公平锁
- ReentrantLock两者都可以,默认非公平锁,构造方法可以传入boolean值,true为公平锁,false为非公平锁
- 锁绑定多个条件condition
- synchronized没有
- ReentrantLock用来实现分组唤醒需要唤醒的线程们,可以精确唤醒,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程
- 此时就要用lock实现:
线程类:
资源类:
虚假唤醒情况
不要用if来判断,必须用while:
知识点结合版代码案例:
代码太多了暂时还没有复现,原作视频,最好自己实现一下,有助加深理解,44_线程通信之生产者消费者阻塞队列版_哔哩哔哩_bilibili
Callable接口
只有runnable有些情况不适用,在并发异步的情况下出现了callable,
线程池
优势:
架构:
Executors工具类
只要是池子,使用完必须关闭!!!
- Executors.newFixedThreadPool(int)
一池固定数线程
可以submit,也可以execute:
- Executors.newSingleThreadExecutor()
一池单线程
- Executors.newCachedThreadPool()
一池多线程
去掉时间停顿:
线程池底层原理
底层都是new了ThreadPoolExecute,都是用阻塞队列实现
选型:
- Executors.newFixedThreadPool(int)执行长期的任务,性能好很多
- Executors.newSingleThreadExecutor()-一个任务一个任务执行的场景
- Executors.newCachedThreadPool()适用:执行很多短期异步的小程序或者负载较轻的服务
线程池七大参数
- corePoolsize:线程池中的常驻核心线程数
- maximumPoolsize:线程池能够容纳同时执行的最大线程数,此值必须>=1
- keepAliveTime:多余的空闲线程的存活时间。当前线程池数量超过corePoolsize时,当空闲时间达到keepAliveTime值时,多余空闲线程会被销毁直到只剩下corePoolsize个线程为止
- unit:keepAliveTime的单位。
- workqueue:任务队列,被提交但尚未被执行的任务。
- threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的!
- handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数时所选策略
- 案例分析:
线程池就像银行,阻塞队列就是窗口,队列容量就是剩余窗口数量,第一个参数就是今日值班的窗口数,最大数量就是最大可值班窗口数,现在12任务来,分别占两条线程执行,345停在阻塞队列等待执行,此时突然来了678,
678是后来任务,此时阻塞队列满,就需要通知另外三个窗口线程赶紧来加班,会直接抢占加班窗口
keepalivetime,当空闲时间达到阈值,会自动销毁多余线程,既关闭后面三个服务窗口,从maximumPoolsize到corepoorsize:
底层原理
处理流程:
- 1.在创建了线程池后,等待提交过来的任务请求,
- 2.当调用 execute()方法添加一个请求任务时,线程池会做如下判断:
2.1 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务;
2.2 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列2.3 如果这时候队列满了且正在运行的线程数量还小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务
2.4 如果队列满了且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。
- 3.当一个线程完成任务时,它会从队列中取下一个任务来执行。
- 4.当一个线程无事可做超过一定的时间(keepAliveTime)时,线程池会判断:
如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。
所以线程池的所有任务完成后它最终会收缩到 corePoolsize 的大小。
既线程池第七个参数:
- AbortPolicy(默认): 直接抛出 RejectedExecutionException异常阻止系统正常运行。
- CalerRunsPolicy: “调用者运行",一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者。
- DiscardoldestPolicy: 抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务。
- DiscardPolicy: 直接丢弃任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种方案。
executors中的三个线程池 ,面试官会问工作中用哪个(超级大坑!!!!),回答是一个都不用,原因可以参考阿里开发手册:
当循环8次,可以运行,但是加到9个,直接报错(默认AbortPolicy)
合理线程数怎么设置
先调用以下方法,看本公司用的服务器cpu是几核的
实际情况分为IO密集型和CPU密集型:
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力干涉那它们都将无法推进下去,如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。
线程操作资源类:
结果:
注意start并不是按顺序来的!!!!
1、在终端通过jps命令查看进程编号
2、jstak查看进程:
也没什么好总结的,所有知识点列个目录吧:
3 原子类AtomicInteger的ABA问题谈谈?原子更新引用知道吗?
4 我们知道ArrayList是线程不安全,请编码写一个不安全的案例并给出解决方案。
5 公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自旋锁
6 CountDownLatch/cyclicBarrier/semaphore使用过吗?
整个JUC大概知识到此完结,因为没有自己编码实现Demo,使用都用贴图的方式展示具体代码,截图均来自尚硅谷教学视频,个人总结笔记用于自己复习记录(所以没有认真做笔记可能别人看起来会很费劲hhhh),但也分享给大家参考参考;
原视频55_死锁编码及定位分析_哔哩哔哩_bilibili(讲的挺好的,推荐大家有时间可以去看完课程,毕竟别人的笔记只有别人自己才能百分百吸收,自己想要最大化汲取知识得要写出自己的笔记效果才好,加油!)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。