JUC:
    1、java.util.concurrent 解决并发编程问题,多线程。提升java的整个并发编程方案
    java.util.concurrent: 核心功能 (线程池、阻塞队列、线程工厂、异步编排….)
    java.util.concurrent.atomic 原子类 (专门为一些常见的基本类型变量设计了原子类操作)
    java.util.concurrent.locks 锁(各种锁, 粒度更细的锁)

    以前:synchronized【锁升级…………】
    缺点:不太灵活,效率低下
    synchronized(){
    if(){
    return
    }
    }

    synchronized func(){} //串行化
    //运行完成以后锁由jvm进行释放

    难点:
    1)、线程
    2)、资源,做业务()
    3)、锁
    设计模式:单一职责原则;领域对象(DDD【Domain Driven Design】== dao、vo、to、dto、po、do。。。。)



    2、进程和线程
    进程:比较大, 一个进程就是一个启动的完整程序 ps -ef 进程 【进程是隔离的】
    微服务:微服务是一种软件架构,每个微服务运行在自己的进程内

    线程:一个进程在处理程序的时候,为了快(为了同时做更多的事情),开了多个线程。
    多个线程可以并发/行处理业务。
    线程间通信: wait(),notify(),notifyAll();
    线程间数据共享: 任意技术(Map)、
    同一线程整个链路共享数据:ThreadLocal(同一个线程的整个链路) …..




    3、并发和并行
    并发:淘宝双11 高并发
    并发底层还是,串行处理,但是由于CPU时间片转的快,让我们觉得在同时处理
    恢复现场:多线程并不是线程越多越好。适量才是最好


    并行:互不影响;


    4、wait/sleep
    wait: 线程等待 wait()/notify(); 【释放锁】
    sleep: 线程睡眠; 【不释放锁】。
    共同效果:调用以后,线程就看着好像不往下执行了。

    5、创建线程回顾
    如何启动一个线程?
    1、继承Thread
    2、实现Runnable
    3、实现Callable

    4、线程池创建

    6、Lambda表达式


    7、synchronized
    卖票:防止超卖
    线程 操作(卖票)Dao/Service 资源类(票)bean
    【线程 操作 资源类】

    空调:
    分: 资源类(空调) + 遥控器
    不分: 类(属性+成员方法)


    8、锁:
    多线程共用一把锁就能解决竞争
    1)、public synchronized void sale()
    2)、synchronized (this){}

    总结:
    1)、synchronized 在 成员方法上的时候。锁住了方法。
    谁是锁?锁就是调用这个方法的对象。 也就是this
    2)、synchronized 在 静态方法上的时候。锁住了方法。
    谁是锁?锁就是这个静态方法所在的类,类在方法区只有一份;
    3)、synchronized 代码块 随便来
    synchronized (this){}
    synchronized 是 可重入设计

    9、如何写多线程?
    线程 操作 资源类
    锁的设计。轻量

    总结:资源竞争的时候,同一把锁就锁住了,否则多线程就不安全;




    【可重入锁】: this
    Class SixSixSix{
    synchronized a(){
    Thread.currentThread.getId();
    b(){
    Thread.currentThread.getId();

    }
    }

    synchronized b(){
    }
    }


    所有的锁都应该设计为可重入的,否则就有可能死锁




    10、java.util.concurrent.locks 专门准备了很多锁。
    Condition: wait()/notify();
    Lock: 锁
    ReentrantLock: 可重入锁
    ReadWriteLock: 读写锁
    ReentrantReadWriteLock: 可重入读写锁




    11、ReentrantLock 可重入锁
    1)、在任意需要加锁的位置 lock.lock();
    2)、事情做完以后 lock.unlock();
    3)、可以随便重复加,自动判断之前加过,就累计数量
    4)、加锁与解锁一定成对出现。
    5)、其他用法
    1)、不同的加锁姿势
    boolean lock = lock.lock(); //加锁 一直阻塞,到加锁成功
    boolean lock = lock.tryLock(); //尝试加锁 不阻塞,立即得到锁的结果
    boolean lock = lock.tryLock(3, TimeUnit.SECONDS); //带时间的尝试加锁 有限阻塞,最多等3秒。 得到锁的结果

    2)、加锁就得解

    6)、模式代码
    第一种模式
    xxx(){
    lock.lock();
    try{
    //业务代码
    }finally{
    lock.unlock();
    }
    }

    第二种模式
    xxx(){
    boolean b = lock.tryLock(..);
    if(b){
    try{
    //业务逻辑
    }finally{
    lock.unlock();
    }
    }else{
    //没得到锁
    }
    }



    12、公平锁?
    非公平锁: 以前多个线程抢锁,谁能抢到无法预测
    公平锁: 多个线程如果在抢锁,锁释放以后,等锁等的最久的人应该最优先抢到,可以一定程度有序 Lock(true); 底层使用队列维护即可


    13、ReentrantLock 与 synchronized
    相同点:
    都是可重入的,独占锁(排他锁、非共享锁)
    不同点:
    1)、ReentrantLock解锁需要手动【加锁解锁一定成对出现】,synchronized 自动解锁
    2)、ReentrantLock 更加灵活。synchronized 的灵活性需要设计代码块,代码块多了不灵活
    3)、ReentrantLock 功能更强。ReentrantLock可以限时等待式阻塞, synchronized 一直等待阻塞
    4)、ReentrantLock 可以实现公平锁。synchronized 加锁 看心情




    14、ReadWriteLock rwLock = new ReentrantReadWriteLock(); //藏了一对读写锁
    rwLock.readLock(): 读锁
    rwLock.writeLock():写锁
    1、写加写锁,读加读锁
    2、只要有写都互斥
    写写互斥
    写读互斥
    读写互斥
    3、只读
    读读共享

    读锁:共享锁 写锁:排他锁
    共享锁就相当于无锁

    new ReentrantReadWriteLock(true); 公平读写锁, 按照等待时长公平竞争

    rwLock.readLock()/writeLock()
    lock();//加锁
    unlock();//解锁
    tryLock();//有限等待加锁


    15、线程间通信
    线程间:多个不同线程
    通信: 一个线程通知其他线程
    wait() 等待 /notify() 通知;

    有锁(synchronized)的环境下才说wait()/notify();
    无锁环境wait()/notify(); IllegalMonitorStateException

    加锁环境下:
    wait() 等待: 等待会释放锁
    notify() 通知:
    sleep() 睡眠: 加锁的环境下,睡眠不放锁。

    sleep和wait相同点
    1、效果都是阻塞。我下面的代码不执行
    sleep 和wait不同点
    1、sleep 不放锁,睡醒接着干
    2、wait 放锁。
    3、notify() 通知、唤醒。 notify();//唤醒一个 notifyAll();//唤醒多个
    被唤醒以后,代码必须从 wait()以后执行,锁还得抢;
    notify();/ notifyAll(); 最终还是只有一个人能抢到


    wait()必有notify()/All()



    多线程:
    1、线程 操作 资源类
    2、判断(等待判断) 干活(执行业务) 去通知(通知别人)

    虚假唤醒
    原因:只要这个线程被唤醒,从wait后开始执行。导致其实唤醒了以后,可执行条件并没有达到。
    解决:把wait条件的if换成while
    synchronized == wait == notify/notifyAll
    在同一个锁对象上候着的所有线程。
    其实 wait/notify 是 锁对象的wait/notify


    synchronized == wait == notify/notifyAll
    lock == Condition.await === Condition.signal
    物理Condition, xxCondition.await(); 会被 xxCondition.signal(); 拉起。用于精确唤醒
    拉起以后。await()下面开始执行




    lock==Condition
    //作业 2个歌手。大合唱。每人一句

    男:夜渐微凉
    女:繁花落地成霜
    女:你在远方眺望
    女:耗尽所有暮光
    男:不思量 自难相忘
    女:夭夭桃花凉
    女:前世你怎舍下
    男:这一海心茫茫
    合:还故作不痛不痒不牵强
    合:都是假象
    合:凉凉夜色为你思念成河
    合:化作春泥呵护着我
    男:浅浅岁月拂满爱人袖
    女:片片芳菲入水流
    合:凉凉天意潋滟一身花色
    男:落入凡尘伤情着我
    女:生劫易渡情劫难了
    女:折旧的心 还有几分前生的恨
    合:还有几分 前生的恨


    //线程操作资源类. 像极:Tomcat 一个请求一来 new Thread(Controller/Service).start()
    //判断(等待判断) 干活(执行业务) 去通知(通知别人)

    wait == notify/notifyAll / Condition.await === Condition.signal
    等: 释放锁,让出CPU
    notify: 唤醒别人
    唤醒以后: CPU、锁

    虚假唤醒 + 植物等待


    16、多线程集合类
    Collection(单值)
    List
    Set
    Queue
    Map(键值对)
    1)、普通的集合类,Map都会有线程安全问题
    ConcurrentModificationException:并发修改异常

    ArrayList是如何给里面添加元素

    安全的:
    List: Vector 和 SynchronizedList 和 CopyOnWriteArrayList【浪费空间】
    Set: synchronizedSet、没有轻量的; 只需要给hashCode计算的时候加锁;
    Map: synchronizedMap、ConcurrentHashMap

    synchronized集合类比较重量级;
    ConcurrentHashMap、CopyOnWriteArrayList

    SpringBoot应用

    @RestController
    Controller{
    }


    @Prototype()//多实例,就可以不用关系多线程资源竞争问题
    @Service
    xxxService{
    private ConcurrentHashMap map = new ConcurrentHashMap();

    void handle(){
    //map.put
    dao.aaa(){
    int i = 1;
    }
    }
    }

    1)、Tomcat 有一个,启动后SpringBoot应用有一个,Spring容器有一个,默认每个组件都是单实例
    2)、请求一来 Tomcat 分配一个线程处理请求,请求很多,就是多线程调用,单实例对象资源会竞争;
    3)、 @Prototype(type=Singleton/Prototype); 不要靠他,浪费内存



    17、常用的几个
    CountDownLatch: 闭锁。 一直减到0,放行一起等待的 就结束
    CyclicBarrier: 循环栅栏。 一直加到N,放行以前等待的 可重置
    Semaphore: 信号量。 可加可减, acquire获取信号没有就等待, 可重置
    限流:
    boolean b = semaphore.tryAcquire();//尝试获取一个
    if(b){
    //调用业务
    }else {
    return “服务器正忙,请稍后…”;
    }


    18、Callable
    class MathCalculator implements Callable{
    //
    @Override
    public Integer call() throws Exception {
    int i = 0;
    i++; //1
    ++i; //2
    System.out.println(Thread.currentThread().getName()+”==>call执行了”);
    return i++;
    }
    }

    FutureTask task = new FutureTask(Callable的对象);
    new Thread(task).start();

    =============Callable的使用==================,
    FutureTask futureTask = new FutureTask<>(()-> 1); //FutureTask 传入Callable
    new Thread(futureTask).start();
    Integer i1 = futureTask.get();//阻塞式获取值
    Integer i2 = futureTask.get(1, TimeUnit.SECONDS); //限时等待
    boolean done = futureTask.isDone(); //查看Task是否完成
    if(done){

    }
    boolean cancelled = futureTask.isCancelled(); //线程是否已经被取消了,中断了
    futureTask.cancel(true);// 强制取消任务
    19、BlockingQueue
    多线程用的多; BlockingQueue 整个系列是有锁的
    队列的普通操作:(操作不了抛异常)
    add(e): 添加元素 从队尾添加一个数据 异常:(加满了)
    remove(): 移除元素 从队头取出并移除这数据 返回移除的元素 异常:(队列是空的)
    element(): 读取队头元素值 从队头获取一个数据 返回队头元素的值 异常:(队列是空的)

    队列的特殊返回值
    offer(e): 添加元素 会返回成功与失败 true/false
    poll(): 移除元素 会返回被移除的元素 队列是空的就null
    peek(): 读取队头元素值 会读取队头的元素值 队列是空的就null

    队列的阻塞功能
    put(e): 添加元素 队列满了,就会一直等待
    take(): 移除元素 会返回被移除的元素 队列是空的一直等待

    队列的限时阻塞功能
    offer(e,long,TimeUnit): 添加元素 队列满了,会等待指定的时间
    poll(time, unit) 移除元素 队列空了,会等待指定的时间



    1)、数组、链表
    数组:移动式添加内容很慢,找东西都慢;
    连续空间
    链表:移动式添加内容很块,找东西都慢;
    碎片化空间
    小数据量用数组
    中大数据量用链接(利用碎片化空间)
    2)、PriorityBlockingQueue 优先级队列
    PriorityBlockingQueue queue = new PriorityBlockingQueue<>(5);
    queue.add(8);
    queue.add(1);
    queue.add(4);
    queue.add(7);
    queue.add(16);

    for (int i = 0; i < 5; i++) {
    Integer remove = queue.remove();
    System.out.println(remove);
    }

    20、ThreadPool 线程池
    new Thread().start(); //资源耗尽
    无休止的new Thread(),很容易资源耗尽。线程池为了控制资源的

    拒绝策略:
    ThreadPoolExecutor.AbortPolicy(): 线程池都满了,还给线程池提交任务,就会抛RejectedExecutionException
    ThreadPoolExecutor.CallerRunsPolicy(): 不拒绝提交的任务。让任务直接运行
    ThreadPoolExecutor.DiscardPolicy(): 忽略,装聋子,啥都不干。任务丢了,但啥都不说
    ThreadPoolExecutor.DiscardOldestPolicy() 移除队列最老的任务,把新提交的任务放进行




    21、volatile
    保证可见性、顺序性
    不保证原子性
    1)、轻量级的同步机制

    22、Atomic:原子类
    所有操作都是利用 UnSafe;直接操作内存;

    //JVM自己会管理内存。但是这种直接操作内存的,JVM就管理不到了。需要自己开辟和释放
    public native void putAddress(long address, long value); //内存地址、存的数据
    public native long allocateMemory(long var1); //字节为单位, allocateMemory(1024) //申请1KB内存。返回内存的起始地址
    public native long reallocateMemory(long var1, long var3);
    public native void freeMemory(long var1);//释放内存,传入地址, 1字节

    //内存屏障
    public native void loadFence();
    public native void storeFence();
    public native void fullFence();

    //CompareAndSwap:比较交换技术
    public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
    public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
    //无锁自旋+比较交换

    //操作系统
    public native void unpark(Object var1); //唤醒
    public native void park(boolean var1, long var2); //阻塞等待

    23、CAS:CompareAndSwap 比较并交换
    Unsafe 类提供的硬件层的原子操作

    CAS:为锁设计的时候,提供竞争修改状态位的

    AtomicInteger: 0 底层全靠 Unsafe,Unsafe 全靠 C,C全靠汇编,汇编全靠01, 01全靠高低电信号,电信号全靠电
    incrementAndGet(){
    int i = unsafe.getAndAddInt(this, valueOffset, 1); //先Get再Add 1;内存告诉我们当时给这个i加的1
    return i + 1;
    }

    24、AQS:(AbstractQueuedSynchronizer)抽象队列同步器
    锁的底层:是通过CAS竞争state + 队列
    队列(数据库): 所有要竞争state的人,如果有人抢到锁,其他人(线程)得等(在队列里面等),当锁被释放以后,从队列里面唤醒一个线程继续执行

    ReentrantLock implements Lock{
    Sync sync;//同步器,是 AbstractQueuedSynchronizer 的实现
    同步器有两种实现
    NonfairSync:非公平
    FairSync: 公平

    }

    AbstractQueuedSynchronizer: 提供了所有的基本操作。使用模板设计模式
    AQS:
    ①提供了一个队列(CLH 锁队列);维护抢锁的所有线程;而且维护了所有的公共逻辑。
    CLH 第一次排队的时候,才初始化这个队列的头尾,为了节省空间;
    头尾节点是两个new Node() 【两个虚拟节点】
    ②CLH 锁队列里面每一个元素是一个Node(节点)【定义好的数据结构】
    【线程、prev、next、waitStatus】整个Node是一个双向列表
    ③提供state;锁的标志位 0:代表没人抢; 大于0的其他值:代表已经有人占用了
    ④提供了 protected 的几个方法,如果直接调用会 throw new UnsupportedOperationException();
    tryAcquire(): 尝试获取量
    tryRelease(): 尝试是否量
    tryAcquireShared(): 尝试获取共享量
    tryReleaseShared(): 尝试释放共享量
    isHeldExclusively(): 判断当前是否排他锁
    ⑤我们可以自定义一个类,继承AbstractQueuedSynchronizer并重写 提供的几个 protected 方法。就能实现自定义占锁/释放锁
    ⑥研究Sync、FairSync、NonfairSync



    25、Lock里面有什么?
    1、CLH队列
    每一个Node
    2、state

    1)、AQS底层靠 CLH队列
    2)、CLH队列 维护Node数据结构(双链表)
    3)、所有线程竞争 state 标志位【利用CAS(原子性)】
    4)、可重入锁,判断如果当前线程就是之前占了锁的线程,那就给 state + 1
    注意:lock了几遍就unlock几遍。state变不成0就死锁了。
    一次解锁就ok;
    5)、公平锁/非公平锁
    非公平锁上来就CAS,先试一下能不能直接改state;改不了就排队
    公平锁上来就挨个排队


    26、synchronized 锁升级的过程;
    JVM在底层进行了优化;
    锁(0/1/2)
    1、如果给一个代码块/方法加上了 synchronized。
    2、【偏向锁】 : 代码在运行的时候,锁是 偏向锁。JVM发现只有一个线程在运行这个代码块,这个线程继续执行,锁就默认就是他的
    3、【轻量级锁】: 第二个线程进来也运行 synchronized,牵扯到抢锁,第二个抢锁的线程看到标志位是1,以自旋while(true){}的方式获取锁
    4、【重量级锁】:如果有更多的线程,自旋了很多次(10)都获取不到锁,jvm让线程wait;
    线程切换最浪费时间和空间的。

    偏向锁 —-> 轻量级锁 —-> 重量级锁;