3. 并发编程 (慕课视频)

1 导读

基础知识
在这里插入图片描述

1 并发线程安全

在这里插入图片描述

1.1 JUC( java.util.concurrent ,java并发包)

在这里插入图片描述

1.2 JUC组件

juc 并发的原子类、集合、锁、tool(countdownlunch)、线程池相关(Future,Executor)
在这里插入图片描述

1 原子类
AtomicInteger:原子性的修改,基于(cas)
2 集合
1. CopyOnWriteArrayList(读多写少,不加锁,写不阻塞读,但是写会阻塞写,修改时复制一份,修改复制的新的,修改引用)
2. ConcurrentHashMap (hash,减少锁的范围,数组+链表+红黑树)
3. ConcurrentSkipListMap(跳表)
3 tool

在这里插入图片描述

  • CountDownLatch:使当前线程在锁存器倒计数至零之前一直等待,countDown()方法计数减一,调用await()方法进行阻塞,等待在调用await的位置处(可以设置超时时间)
  • CyclicBarrier:调用await()方法计数加1,未达到时阻塞,计数达到指定值时释放所有等待线程,可重复性
    CountDownLatch和CyclicBarrier都有让多个线程等待同步然后再开始下一步动作的意思,但是CountDownLatch的下一步的动作实施者是主线程,具有不可重复性;而CyclicBarrier的下一步动作实施者还是“其他线程”本身,具有往复多次实施动作的特点。
  • Semaphore:信号量,acquire()获取一个许可,release()释放一个许可,当达到指定数量时会阻塞
    new Semaphore(3);
  • Exchanger:两个线程之间交换信息,exchanger.exchange(),主要用于管道通讯等两两交换比对的场景。
4 线程池相关:Executors.newFixedThreadPool(2),线程池工厂类
 1. Future,FutureTask(异步)
 2. Executor(线程池),Executors是其工厂类
 3. TimeUnit 
 ExecutorService executorService = new ThreadPoolExecutor(1,1,10,TimeUnit.MINUTES,new LinkedBlockingQueue<>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
5 锁

1.3 高并发处理思路及手段

在这里插入图片描述

1.4 JMM

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2 并发线程安全

2.1 线程安全性

在这里插入图片描述
在这里插入图片描述

原子性

在这里插入图片描述
AtomicBoolean 可以 让代码只执行一次
在这里插入图片描述
在这里插入图片描述

可见性

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
volatile不具有原子性,适合做状态标记量和双重检测标记

有序性

在这里插入图片描述
happens-before的八个原则
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 安全发布对象

在这里插入图片描述
在这里插入图片描述
双重检测机制不一定线程安全(指令重排序)

2.3 线程安全策略

  1. 不可变对象
  2. 线程封闭(只有一个线程能看到)
  3. 线程安全的类(StringBuffer,Vector,Stack,Hashtable,ConcurrentHashMap,Collections.synchronizedList等)同步容器每个方法是线程安全的,但是方法混合调用可能出现线程不安全的问题,同步容器性能差,而且不能完全做到线程安全,一般使用并发容器
  4. 线程不安全的类(simpleDateFormat.parse)
  5. 并发容器(JUC,java.util.concurrent)

在这里插入图片描述
修饰引用类型变量时,不允许指向其他对象,但是可以改变对象的值
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

并发容器

在这里插入图片描述
Skiplist
COW(读多写少,写的时候写到新的数据结构,牺牲数据实时性满足数据的最终一致性即可)

2.4 线程安全对象策略

在这里插入图片描述
在这里插入图片描述

2.5 JUC的AQS(AbstractQueuedSynchronizer抽象队列同步器)

AQS

在这里插入图片描述
aqs的等待队列(上)
condition的等待队列(下)
condition.await()从上面的队列加入下面
condition.signalAll();从下面的加入上面

AQS同步组建
  1. CountDownLatch

  2. Semaphore

  3. CyclicBarrier

  4. ReentramtLock

  5. Condition

  6. FutureTask

     1. countDownLatch(等待所有线程执行完之后再执行之后的操作)
        countDownLatch.await();
        countDownLatch.await(10, TimeUnit.MILLISECONDS);
     2. Semaphore(控制并发访问的个数,仅能提供有限访问的资源)
     	 semaphore.acquire(); // 获取一个许可
          semaphore.release(); // 释放一个许可
     	 semaphore.acquire(3); // 获取多个许可
     	 semaphore.tryAcquire())  // 尝试获取一个许可(拿不到许可直接丢弃)
     	 semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS))  // 尝试获取一个许可,等待一秒
     3. CyclicBarrier(多个线程相互等待,每个线程都准备就绪后才往后执行)
         与countDownLatch区别
         	计数器可以重用
         	多个线程相互等待
         barrier.await();
     4. ReentrantReadWriteLock(读多写少的时候,容易饥饿)(学)
     	StampedLock(学)
     选择:
     	少量竞争者的时候synchronized(不会死锁)
     	有其他ReentrantLock特有功能时使用ReentrantLock
    

在这里插入图片描述

2.6 JUC的组件拓展

FutureTask

Future获取线程返回值
FutureTask实现RunnableFuture,RunnableFuture继承了Runnable和Future

Fork / Join

工作窃取算法
在这里插入图片描述

            // 执行子任务
            leftTask.fork();
            rightTask.fork();

            // 等待任务执行结束合并其结果
            int leftResult = leftTask.join();
            int rightResult = rightTask.join();

BlockingQueue

适用场景:生产者消费者

线程池

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Executors.newCachedThreadPool();
Executors.newScheduledThreadPool();调度,可以设置间隔时间执行

在这里插入图片描述
当线程池中的任务很小,小到任务执行时间和调度任务的时间都接近时,使用线程池速度反而会降低

多线程并发

在这里插入图片描述

解决方案
顺序加锁
锁加上时间

3.7 最佳实践

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
spring中controller,service等线程安全主要是无状态对象
在这里插入图片描述
java7的Segment
在这里插入图片描述
java8引入红黑树,去掉Segment
在这里插入图片描述

3 高并发处理思路及手段

扩容

在这里插入图片描述
多个机房
在这里插入图片描述
异地多机房
在这里插入图片描述

缓存

在这里插入图片描述
1到4都可以加缓存
缓存读多写少,实时性低
缓存技术选型:本地缓存容易出现单机瓶颈,分布式缓存易于扩展
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
memcache服务端不支持分布式,依赖客户端的一致性hash算法做分布式
在这里插入图片描述
单个item最大的数据时1Mb
在这里插入图片描述
redis数据支持持久化,数据结构类型丰富,数据备份,高性能,原子性


        LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
                .maximumSize(10) // 最多存放10个数据
                .expireAfterWrite(10, TimeUnit.SECONDS) // 缓存10秒
                .recordStats() // 开启记录状态数据功能
                .build(new CacheLoader<String, Integer>() {
                    @Override
                    // 默认的返回值
                    public Integer load(String key) throws Exception {
                        return -66;
                    }
                });

在这里插入图片描述

  1. 缓存穿透
    正常情况下,查询的数据都存在,如果请求一个不存在的数据,也就是缓存和数据库都查不到这个数据,每次都会去数据库查询,这种查询不存在数据的现象我们称为缓存穿透
    解决方案缓存空对象
  2. 缓存击穿
    在高并发的情况下,大量的请求同时查询同一个key时,此时这个key正好失效了,就会导致同一时间,这些请求都会去查询数据库,这样的现象我们称为缓存击穿
    解决方案
    采用分布式锁,只有拿到锁的第一个线程去请求数据库,然后插入缓存,当然每次拿到锁的时候都要去查询一下缓存有没有
  3. 缓存雪崩
    当某一时刻发生大规模的缓存失效的情况
    解决方案
    设置不同的失效时间
    采用缓存击穿的解决办法,加锁
    永不失效,就是采用定时任务对快要失效的缓存进行更新缓存和失效时间
    在这里插入图片描述
    在这里插入图片描述

消息队列

在这里插入图片描述
不适用延迟很敏感以及强事务保证的场景
在这里插入图片描述
在这里插入图片描述

应用拆分

按功能模块

 缺点
  	管理麻烦
	网络开销

在这里插入图片描述
在这里插入图片描述

同步
	rest(HTTP)
	rpc(dubbo)
异步
	消息队列


服务发现
	zookeeper

服务挂了
	熔断,限流,降级

限流

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
漏桶 VS 令牌桶
令牌桶可以应对突发请求,漏桶只能以恒定速率

  1. 单机版限流(Guava RateLimiter)
   //每秒允许5个请求
    private static RateLimiter rateLimiter = RateLimiter.create(5);
    //间隔201毫秒获取令牌。获取不到就不获去了
    rateLimiter.tryAcquire(201, TimeUnit.MILLISECONDS)
    //能保证所有请求被处理
    rateLimiter.acquire();
  1. 分布式限流
redis:incrby key value

降级熔断

通过配置系统(类似配置中心)的配置,确定是否降级,下图的db相当于数据字典

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数据库分库分表等

在这里插入图片描述

第1节你真的了解并发吗? [免费观看][免费观看] 00:27:48分钟 | 第2节理解多线程与并发的之间的联系与区别 [免费观看] 00:11:59分钟 | 第3节解析多线程与多进程的联系以及上下文切换所导致资源浪费问题 [免费观看] 00:13:03分钟 | 第4节学习并发的四个阶段并推荐学习并发的资料 [免费观看] 00:09:13分钟 | 第5节线程的状态以及各状态之间的转换详解00:21:56分钟 | 第6节线程的初始化,中断以及其源码讲解00:21:26分钟 | 第7节多种创建线程的方式案例演示(一)带返回值的方式00:17:12分钟 | 第8节多种创建线程的方式案例演示(二)使用线程池00:15:40分钟 | 第9节Spring对并发的支持:Spring的异步任务00:11:10分钟 | 第10节使用jdk8提供的lambda进行并行计算00:14:22分钟 | 第11节了解多线程所带来的安全风险00:13:16分钟 | 第12节从线程的优先级看饥饿问题00:18:42分钟 | 第13节从Java字节码的角度看线程安全性问题00:25:43分钟 | 第14节synchronized保证线程安全的原理(理论层面)00:13:59分钟 | 第15节synchronized保证线程安全的原理(jvm层面)00:25:03分钟 | 第16节单例问题与线程安全性深入解析00:27:15分钟 | 第17节理解自旋锁,死锁与重入锁00:24:58分钟 | 第18节深入理解volatile原理与使用00:28:30分钟 | 第19节JDK5提供的原子类的操作以及实现原理00:27:10分钟 | 第20节Lock接口认识与使用00:19:54分钟 | 第21节手动实现一个可重入锁00:26:31分钟 | 第22节AbstractQueuedSynchronizer(AQS)详解00:49:04分钟 | 第23节使用AQS重写自己的锁00:31:04分钟 | 第24节重入锁原理与演示00:12:24分钟 | 第25节读写锁认识与原理00:18:04分钟 | 第26节细读ReentrantReadWriteLock源码00:30:38分钟 | 第27节ReentrantReadWriteLock锁降级详解00:13:32分钟 | 第28节线程安全性问题简单总结00:15:34分钟 | 第29节线程之间的通信之wait/notify00:32:12分钟 | 第30节通过生产者消费者模型理解等待唤醒机制00:20:50分钟 | 第31节Condition的使用及原理解析00:17:40分钟 | 第32节使用Condition重写wait/notify案例并实现一个有界队列00:22:05分钟 | 第33节深入解析Condition源码00:21:15分钟 | 第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析00:10:17分钟 | 第36节ThreadLocal 使用及实现原理00:17:41分钟 | 第37节并发工具类CountDownLatch详解00:22:04分钟 | 第38节并发工具类CyclicBarrier 详解00:11:52分钟 | 第39节并发工具类Semaphore详解00:17:27分钟 | 第40节并发工具类Exchanger详解00:13:47分钟 | 第41节CountDownLatch,CyclicBarrier,Semaphore源码解析00:29:57分钟 | 第42节提前完成任务之FutureTask使用00:11:43分钟 | 第43节Future设计模式实现(实现类似于JDK提供的Future)00:19:20分钟 | 第44节Future源码解读00:29:22分钟 | 第45节Fork/Join框架详解00:28:09分钟 | 第46节同步容器与并发容器00:18:44分钟 | 第47节并发容器CopyOnWriteArrayList原理与使用00:15:52分钟 | 第48节并发容器ConcurrentLinkedQueue原理与使用00:31:03分钟 | 第49节Java中的阻塞队列原理与使用00:26:18分钟 | 第50节实战:简单实现消息队列00:11:07分钟 | 第51节并发容器ConcurrentHashMap原理与使用00:38:22分钟 | 第52节线程池的原理与使用00:42:49分钟 | 第53节Executor框架详解00:36:54分钟 | 第54节实战:简易web服务器(一)00:55:34分钟 | 第55节实战:简易web服务器(二)00:24:36分钟 | 第56节JDK8的新增原子操作类LongAddr原理与使用00:17:45分钟 | 第57节JDK8新增锁StampedLock详解00:29:37分钟 | 第58节重排序问题00:23:19分钟 | 第59节happens-before简单概述00:15:17分钟 | 第60节锁的内存语义00:13:54分钟 | 第61节volatile内存语义00:12:04分钟 | 第62节final域的内存语义00:34:07分钟 | 第63节实战:问题定位00:07:48分钟 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值