JAVA并发真讨厌(二)
【摘要】 JUC包下,继续根据资料整理那些不曾注意的问题,有些人云亦云的问题,能在大佬的视频中找到答案,着重看下那些颠覆常识的问题,另外,小马哥对源码的熟悉程度实在令人敬佩。 高并发要关注的问题 1.线程安全 2.减少线程同步竞争 3.合理利用状态位 4.线程池 5.超时意识 **1.什么是线程安全问题...
JUC包下,继续根据资料整理那些不曾注意的问题,有些人云亦云的问题,能在大佬的视频中找到答案,着重看下那些颠覆常识的问题,另外,小马哥对源码的熟悉程度实在令人敬佩。
高并发要关注的问题
1.线程安全
2.减少线程同步竞争
3.合理利用状态位
4.线程池
5.超时意识
**1.什么是线程安全问题?**
答:多线程并发执行时,对共享内存中共享对象的属性发生修改时所导致的数据冲突问题,称之为线程安全问题
2.线程池:所有的池化操作,我都理解为将要执行的资源放入,减少其创建与销毁的时间,且能动态的去定制获取策略,空闲策略等。
从CountDownLatch,CyclicBarrier,Semaphore入手
以前已经总结过关于这三个线程操作的文章[CountDownLatch 与 CyclicBarrier 和Semaphore的区别?](https://mp.weixin.qq.com/s?__biz=Mzg2ODA3NjA1MA==&mid=2247484325&idx=1&sn=7998b47b95bc706c27acebf6dab6e342&chksm=ceb09cd8f9c715cef11aa17a0d04191ec5f8cad3fec3a2f3b8f862b8ad2b18e9ca6861e6919e&token=1435792401&lang=zh_CN&scene=21#wechat_redirect)现在看下内部操作
CyclicBarrier:
![请在此添加图片描述](https://ask.qcloudimg.com/http-save/4069641/j6rphc8tsd.png?qc_blockWidth=332&qc_blockHeight=404)
reset:
重置,刷新操作,reset不要轻易去用
breakBarrier :
```javascript
private void breakBarrier() { generation.broken = true; count = parties; trip.signalAll(); }
```
nextGeneration:
```javascript
Updates state on barrier trip and wakes up everyone//更新线程状态并唤醒
```
项目中用于countdownLatch更多,慎用CyclicBarrire
**3.线程池 THREADPOOL**
1.线程复用
2.控制最大并发数
3.管理线程
**-ExecutorService的实现**
1.ThreadPoolExecutor
2.ScheduleThreadPoolExecutor
3.ForkJoinPool
**-常见的创建线程池的方式5种**
但常用3种,在阿里巴巴开发手册中指定
```javascript
【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。说明:Executors 返回的线程池对象的弊端如下:1)FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。2)CachedThreadPool 和 ScheduledThreadPool:允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
```
实际谁也不会用到Integer.MAX\_VALUE(),但是CacheThreadPool就不一定了,他不会指定线程数量,所以一旦获取线程是循环会有可能到到这个数量
![请在此添加图片描述](https://ask.qcloudimg.com/http-save/4069641/ges8mwlgfd.png?qc_blockWidth=594&qc_blockHeight=251)
**--线程7参**
```javascript
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
```
在常用3种线程池中只有5参,看下全参
![请在此添加图片描述](https://ask.qcloudimg.com/http-save/4069641/cy5tav75kr.png?qc_blockWidth=761&qc_blockHeight=293)
```javascript
new ThreadPoolExecutor(1, 2, 0, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(3), new ThreadPoolExecutor.AbortPolicy() );
```
看下idea默认提示
![请在此添加图片描述](https://ask.qcloudimg.com/http-save/4069641/wvj6gh0gl5.png?qc_blockWidth=801&qc_blockHeight=214)
线程7参已经总结过了[线程7参](https://mp.weixin.qq.com/s?__biz=Mzg2ODA3NjA1MA==&mid=2247483985&idx=1&sn=1566a15353ae1f31b23420483f060a8c&chksm=ceb09d2cf9c7143ab6cb1e57697a3fa7d07d59cec7ce166e4a6e3f70550efbcc4fbb89ef6b5b&token=1435792401&lang=zh_CN&scene=21#wechat_redirect)
**4:如何获取正在运行的线程?**
![请在此添加图片描述](https://ask.qcloudimg.com/http-save/4069641/qilnryra6n.png?qc_blockWidth=414&qc_blockHeight=415)
ThreadPoolExecutor是有before,after方法的,但是针对
newCachedThreadPool如何获取呢?
```javascript
public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); Set<Thread> threads = new HashSet<>(); //计数 setFactory(executorService, threads); for (int i = 0; i < 9; i++) { executorService.submit(() -> { }); } executorService.awaitTermination(10, TimeUnit.MILLISECONDS); // System.out.println("线程池等待 \n"+threads); threads.stream() .filter(Thread::isAlive) .forEach(System.out::println); executorService.shutdown(); }
private static void setFactory(ExecutorService executorService, Set<Thread> threads) { if (executorService instanceof ThreadPoolExecutor) { ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService; ThreadFactory threadFactory = threadPoolExecutor.getThreadFactory(); threadPoolExecutor.setThreadFactory(new DelegatingFactory(threadFactory, threads)); } }
private static class DelegatingFactory implements ThreadFactory {
private final ThreadFactory delegate; private Set<Thread> threads;
private DelegatingFactory(ThreadFactory delegate, Set<Thread> threads) { this.delegate = delegate; this.threads = threads; }
@Override public Thread newThread(Runnable r) { Thread thread = delegate.newThread(r); threads.add(thread); return thread; } }
```
运行结果:
```javascript
Connected to the target VM, address: '127.0.0.1:50402', transport: 'socket'Thread[pool-1-thread-5,5,main]Thread[pool-1-thread-9,5,main]Thread[pool-1-thread-3,5,main]Thread[pool-1-thread-7,5,main]Thread[pool-1-thread-6,5,main]Thread[pool-1-thread-4,5,main]Thread[pool-1-thread-2,5,main]Thread[pool-1-thread-8,5,main]Thread[pool-1-thread-1,5,main]Disconnected from the target VM, address: '127.0.0.1:50402', transport: 'socket'
```
**颠覆常识的问题**
**Volatile是保证原子性还是可见性?**
这个问题我看资料总结过无数次,都说只能保证内存可见性,但是
volatile即内存屏障,可保证一段内存中一个变量的原子性,原生类型都是原子性的。所以java中 volatile long,volatile double都是线程安全的。
**为啥Automic volatiel 用的是int value?而不用boolean?**
```javascript
volatile int scanState; volatile int value;
```
因为在底层boolean的实现既是int实现的,所以volatile的set方法即安全的
**CAS锁是比较偏重的操作?**
CAS在操作锁时,执行比较并交换操作,相对synchronized瘦锁是比较重的锁,偏向锁在这里避免了CAS操作。UseBiaseLocking对synchronize有用
**总结:这期总结确实颠覆了以往认知,不管是以往的资料还是面试中很难去得到这样的知识点,当然仁者见仁,佩服的是小马哥对底层的理解,可手撕源码实现,这并非一朝一夕的能力,在平时中的书写也可模仿源码的操作,提高代码的可用性。**
**声明:本文内容根据B站UP主mercyblitz,往期视频以及历史资料整理,扫描二维码关注小马哥公众号,java劝退师,好东西需要分享,干货满满**
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)