前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JAVA并发真讨厌(二)

JAVA并发真讨厌(二)

作者头像
疯狂的KK
发布2019-11-12 14:19:06
3530
发布2019-11-12 14:19:06
举报
文章被收录于专栏:Java项目实战Java项目实战

JUC包下,继续根据资料整理那些不曾注意的问题,有些人云亦云的问题,能在大佬的视频中找到答案,着重看下那些颠覆常识的问题,另外,小马哥对源码的熟悉程度实在令人敬佩。

高并发要关注的问题

1.线程安全

2.减少线程同步竞争

3.合理利用状态位

4.线程池

5.超时意识

1.什么是线程安全问题?

答:多线程并发执行时,对共享内存中共享对象的属性发生修改时所导致的数据冲突问题,称之为线程安全问题

2.线程池:所有的池化操作,我都理解为将要执行的资源放入,减少其创建与销毁的时间,且能动态的去定制获取策略,空闲策略等。

从CountDownLatch,CyclicBarrier,Semaphore入手

以前已经总结过关于这三个线程操作的文章CountDownLatch 与 CyclicBarrier 和Semaphore的区别?现在看下内部操作

CyclicBarrier:

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就不一定了,他不会指定线程数量,所以一旦获取线程是循环会有可能到到这个数量

--线程7参

代码语言:javascript
复制
public static ExecutorService newSingleThreadExecutor() {        return new FinalizableDelegatedExecutorService            (new ThreadPoolExecutor(1,                                     1,                                    0L,                                    TimeUnit.MILLISECONDS,                                    new LinkedBlockingQueue<Runnable>()));    }

在常用3种线程池中只有5参,看下全参

代码语言:javascript
复制
new ThreadPoolExecutor(1,                2,                0,                TimeUnit.SECONDS,                new LinkedBlockingDeque<Runnable>(3),                new ThreadPoolExecutor.AbortPolicy()                );

看下idea默认提示

线程7参已经总结过了线程7参

4:如何获取正在运行的线程?

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劝退师,好东西需要分享,干货满满

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 赵KK日常技术记录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档