栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JUC介绍--狂神视频笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JUC介绍--狂神视频笔记

    先建maven项目,JDK8

    学习方式:源码,官方文档

    什么的JUC java util concurrent

    就是这三个包

    java.util.concurrent
    java.util.concurrent.atomic
    java.util.concurrent.locks
    

    thread只是一个普通的线程类

    runnable 没有返回值,效率比callable低,所以更多用callable

    线程和进程 ,必须要用一句话总结出

    自己:进程是资源分配的基本单位,程序获得CPU分配的资源后才能执行。线程是资源调度的管理者。

    狂神:进程是一个程序,一个进程包含多个线程,Java默认有两个线程(main, GC)


    55533.png" alt=“image-20220324161655533” style=“zoom:67%;” />

    Java开启线程的方式:runnable ,thread,callable

    但是Java无法真正的开启线程

        public Thread(ThreadGroup group, Runnable target, String name,
                      long stackSize) {
            init(group, target, name, stackSize);
        }
    	public synchronized void start(){
            group.add();
                    boolean started = false;
            try {
                start0();
                started = true;
            } finally {
                try {
                    if (!started) {
                        group.threadStartFailed(this);
                    }
                } catch (Throwable ignore) {
                    
                }
            }
        }
    //调用本地方法,所以说明Java没有开启线程的能力,调用底层的C++,Java无法控制硬件
        private native void start0();
        } 
    
    并发和并行的区别

    并发:多线程操作同一个资源,单核CPU,进程切换,快速交替

    并行:多个人一起走,多核CPU,多个线程可以同时运行,线程池

    通过代码查看多核Runtime,输出12个

        public static void main(String[] args) {
       System.out.println(Runtime.getRuntime().availableProcessors());
        }
    

    CPU密集型,IO密集型是什么

    并发编程的本质:重复利用CPU资源

    回顾多线程 线程有几个状态;

    我:运行态、阻塞态、并行态、

    狂:6个

        public enum State {
            
            NEW,
            
            RUNNABLE,
            
            BLOCKED,
            
            WAITING,
            
            TIMED_WAITING,
            
            TERMINATED;
        }
    
    wait方法和spleep区别

    wait占用问题, 锁的问题

      wait来自Object类, sleep来自thread类(企业不会用,企业用 TimeUnit->归属于JUC的Concurrent)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ipuWfTKn-1648363882191)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324164322519.png)]

      锁的释放,wait释放锁,sleep抱着锁睡使用范围不同,wait 必须在同步代码块中 sleep可以在任何地方使用,,,,,是否需要捕获异常;wait会中断异常, sleep要捕获(写代码爆红)
    Lock锁 Synchronized锁

    狂神说有人写多线程方式是这样的,我是, 继承runnable方法,重写run,new一个新的线程

    线程就是一个单独的资源类,没有任何的附属操作

    实现接口就不是OOP了,耦合性极高

    	public static void main(String[] args){
            new Thread;
        }
    	class MyThread implements Runnable{
            @Override
            public void run(){
                
            }
        }
    

    函数式接口, 匿名内部类, JDK1.8后简化为lambda表达式 (方法参数 )->{ 代码}

    并发解耦

    	public static void main(String[] args){
            Ticket ticket = new Ticket();
            new Thread(()->{ticket.sale();}, "A").start();
            new Thread(()->{ticket.sale();}, "B").start();
            new Thread(()->{ticket.sale();}, "C").start();
        }
    

    多个线程用一个资源会发生争抢的现象。

    解决:加Sychronized锁,避免争抢。

    lock是接口,有3个实现类,可重入锁,读锁,写锁

    公平锁:先来后到,

    非公平锁:可以插队,防止饥饿,默认

        public ReentrantLock() {
            sync = new NonfairSync();
        }
    

    如何使用:try业务代码, catch, fanally解锁

    Lock三部曲:

      new ReentantLock();代码块加锁 Lock.lock();finally解锁

    labmda表达式写锁

    Synchronized 和Lock的区别 重要
      Synchronized是内置的java关键字, Lock是一个Java类Synchronized无法判断获取锁的状态, Lock可以判断是否获取到了锁Synchronized会自动释放锁, Lock手动释放。如果不释放,死锁。Synchronized线程不会争抢,线程1不释放,线程2 就一直等待, Lock不会一直等待。Synchronized可重入锁,不可以中断,非公平, Lock可重入,可判断,默认非公平的,但是可以自己设置。Synchronized适合锁少量的代码同步问题, Lock适合所大量的同步代码。
    所以锁是什么,如何判断锁的是谁? 传统的生产者消费者问题,防止虚假唤醒 Synchronized 的 wait notify版本

      线程中的通信问题:生产者消费者,线程交替执行操作同一个变量,即通知和等待唤醒

      等待,业务逻辑,通知

        public static void main(String[] args) {
              Data data = new Data();
            //不要显示创建线程池,用线程池创建线程
            //https://blog.csdn.net/luxing205/article/details/114639313
              new Thread(()->{for(int i = 0; i < 10; i++){
              try {
                  data.decrement();
              }catch (InterruptedException e){
                  e.printStackTrace();
              }
              }
              }, "B").start();
          } 
      
      public class Data{
              private int number = 0;
              public synchronized void increment(){
                  //if判断只会判断一次,所以有两个线程进来的时候会发生问题
                  if (number != 0){
                      //等待
                      this.wait();
                  }
                  number++;
                  //通知其他线程
                  this.notifyAll();
              }
              public synchronized void decrement(){
                  if (number == 0){
                  }
                  number--;
              }
          }
      
      面试基本问题:单例模式,排序算法,生产者消费者,死锁

      上述代码4个线程还安全吗?

      防止虚假唤醒问题,改为while判断

                  //if判断只会判断一次,所以有两个线程进来的时候会发生问题
                  while (number != 0){
                      //等待
                      this.wait();
                  }
      
      JUC版的LOCK 生产者消费者问题

    Synchronized: wait, notify
    Lock: await, signal

    通过Lock找到Condition,lock接管了synchronized, condition取代了对象监视器方法的使用

        public static class Data{
            private int number = 0;
            Lock lock = new ReentrantLock();
            Condition condition = lock.newCondition();
            public void increment() throws InterruptedException {
                lock.lock();
                 try {
                     //业务:判断->执行->通知
                     while (number != 0){
                         condition.await();
                         condition.signalAll();
                     }
                     number++;
                 }catch (Exception e){
                     e.printStackTrace();
                 }finally {
                     lock.unlock();
                 }
            }
    

    任何一个新的技术,绝对不是仅仅覆盖原来的技术,一定有优势。

    Condition可以精准的唤醒和通知线程

    Condition实现精准的唤醒和通知线程

    同步监视器:

    精准唤醒:

    8锁现象 就是关于锁的8个问题

    学习方法:费曼学习法,学习兴趣,学习态度

    什么是锁,锁的是谁

    锁是new出来的, 而对象是由Class模板new出来

    public static void main(String[] args) {
            Phone phone = new Phone();
            //不是由于先调用,而且先调用不代表先执行,而是锁的作用
            new Thread(()->{
                phone.sendSms();
            },"A").start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(()->{
                phone.call();
            },"B").start();
        }
        public static class Phone{
            public synchronized void sendSms(){
                System.out.println("sendSms");
            }
            public synchronized void call(){
                System.out.println("call");
            }
        }
    

    由于这两个方法用的phone这个同一把锁,谁先拿到谁先执行。

    加上TimeUnit.SECONDS.sleep(4)延迟和hello方法不加锁可以影响打印顺序

    没有锁就不是同步方法,不受锁的影响。

    synchronized锁的对象是方法的调用者

     public static void main(String[] args) {
            Phone phone = new Phone();
            //不是由于先调用,而且先调用不代表先执行,而是锁的作用
            new Thread(()->{
                phone.sendSms();
            },"A").start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(()->{
                phone.hello();
            },"B").start();
        }
        static class Phone{
            public synchronized void sendSms(){
                try {
                    //是这里的休眠影响了时间,所以在这里要搞清锁的是谁
                    TimeUnit.SECONDS.sleep(4);
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println("sendSms");
            }
            public synchronized void call(){
                System.out.println("call");
            }
            public void hello(){
                System.out.println("hello");
            }
        }
    
    增加两个静态的同步方法

    静态方法与普通方法的区别:先执行静态方法(static类一加载就有了) + synchronized

    先执行它

            public static synchronized void sendSms(){
                try {
                    TimeUnit.SECONDS.sleep(4);
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println("sendSms");
            }
    

    小结:

    new this 具体的一个对象

    class 具体的模板

    ​ Q:既然不占用CPU为什么占用内存,难道是在后台偷偷运行?

    读取速度:

    CPU -> 内存 -> SSD -> 磁盘 -> 网络
    纳秒 -> 微秒 -> 毫秒 -> 毫秒 -> 秒
    

    那哪些软件会主动存到磁盘?为什么选择存在磁盘?

    集合类不安全 CopyonWriteArrayList 写入时复制

    COW计算机程序设计领域的一种优化策略。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vPLsTtXS-1648363882195)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324224118807.png)]

    单线程的代码永远是安全的

    List多线程下不安全:

    //随机字符串
    list.add(UUID.randomUUID().toString().subString(0,5));
    

    如何解决?即并发安全

      List list = new Vector<>(),不好 list并发下不安全Arrays -> Collections.synchronzedList(new ArrayList<>());List list = new CopyOnWriteArrayList<>();

    一定要自己动手!

    读CopyOnWriteArrayList源码

    list.foreach里面有哪些参数,四大函数式接口 CopyonWriteArraySet HashSet

    BlockingQueue: 阻塞队列

    不安全set 初始:又出现ConcurrentModificationException

    解决措施:

      工具类写法:Set set = Collections.synchronizedSet(new HashSet<>());JUC写法:Set set = new CopyOnWriteArraySet<>();
    HashSet的底层:就是hashmap

    key是无法重复的

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hH0efzx7-1648363882197)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324225656156.png)]

    IO类,集合类,常用类 ConcurrentHashMap

    HashMap也是不安全的 并发异常

    map是这样用的吗,默认等价于什么?

    Map map = new HashMap<>();
    

    加载因子loadFactor=0.75,初始化容量initialCapacity why???

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wp5nVtBP-1648363882198)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324230006824.png)]

    看HashMap源码!!!

    有问题:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4xixEhb-1648363882199)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324231022517.png)]

    synchronized

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8d228Kw6-1648363882200)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324231221044.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8W5Wx2sa-1648363882200)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220324231358310.png)]

    解决:

    Map map = new ConcurrentHashMap<>();
    

    研究ConcurrentHashMap原理!

    Callable 可以返回结果和抛出异常,类似于similar
    @FunctionalInterface
    public interface cllable{
        V call() throws Exception;
    }
        public static class MyThread implements Callable{
            @Override
            public Integer call() throws Exception {
                return 1024;
            }
        }
    

    不要用runnalbe,因为他没有返回值

    implements Callable

    //new Thread(new Runnable()).start();
    //new Thread(new FutureTask()).start();
    //new Thread(new FutureTask(Callable)).start();
    应用:
        new Thread.start();
    	MyThread thread = new MyThread();
    	FutureTask futureTask = new FutureTask(thread); // implements Callable
    	new Thread(futureTask, "A").start();
    	Integer o = (Integer)futureTask.get();
    

    阿里巴巴规范

    分析:

    JDK线程池框架继承关系:

    线程池构造类ThreadPoolExecutor实现方法

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                         	  RejectedExecutionHandler handler) { ... ... }
    

    JDK自带的工具类可以创建的线程池种类

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gjLKDfKe-1648363882201)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325095237983.png)]

    引java.util的包 https://juejin.cn/post/6844904074668670984

    三大常用辅助类,高并发 CountDownLatch 计数器

    减法计数器

    两个方法:

    CountDownLatch.countDown() 数量-1

    CountDownLatch.await 等待计数器归零再向下执行, 防止有些数据未操作完

    每次有线程调用CountDownLatch()数量-1 ,假设计数器变为0, CountDownLatch.await()就会被唤醒,继续执行。

    CyclicBarrier 加法,等待达到数量才会执行

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gwOf4toj-1648363882203)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325110743674.png)]

    <=7代表永远达不到8,就不会开启新的线程

    Semaphore ,信号量 并发

    有个acquire(),假设资源已经满了就等待释放, release方法,信号量释放+1,等待唤醒线程

    计数信号量。 从概念上讲,信号量维护一组许可。 如有必要,每个 acquire() 都会阻塞,直到获得许可,然后再接受它。 每个 release() 添加一个许可,可能会释放一个阻塞的获取者。 但是,没有使用实际的许可对象; Semaphore 只是对可用数量进行计数并采取相应措施。

    Semaphores are often used to restrict the number of threads than can access some (physical or logical) resource.

    抢车位:6个车3个位置,轮流等待车位,用于限流,控制线程最大数,保证高可用。

    并发思想大多与操作系统有关

    ReadwriteLock 读写锁是ReEntrantLock的更加细粒度

    ReentrantReadLock读锁独占 reentrantWriteLock 写锁共享,多个线程同时占有

    只有一个接口 reentrantlock 都可以被多线程读,写只能被一个线程写

    volatile 保证原子性

    private vlatile map map = new HashMap<>();
    map.put写
    map.get读
    
    阻塞队列 队列FIFO

    ElasticSearch

    不得不阻塞:Input读,队列满了,阻塞等待,队列空了,等待生产,阻塞等待

    ArrayBlockingQueue, linkedBlockingQueue

    java中的list和set是什么,父:Collection ->Queue -> BlockingQueue,Abstract(非阻塞),Deque ->Array,linked, , 双端队列是一种具有队列和栈性质的抽象数据类型。 双端队列中的元素可以从两端弹出,插入和删除操作限定在队列的两邊进行。

    什么情况需要用到阻塞队列:

    多线程,线程池的挂起等待,多线程并发处理,线程池

    BlockingQueue的四组API
      抛出异常不会抛出异常阻塞等待超时等待
    方式抛出异常不会抛出异常阻塞等待超时退出
    添加addofferputoffer(timeout)
    移除removepoll空参takepoll(timeout)
    检测队首元素elementpeek
    //队列的大小一定要写
    ArrayBlockingQueue b = new ArrayBlockingQueue<>(3);
    

      2.不抛出异常,返回布尔值

        SychronousQueue同步队列

        隶属于BlockingQueue不存储元素,没有容量,必须等待取出后才能放,即容量为1

        new两个线程,一个负责

        线程池 三大方法、七大参数、4种拒绝策略 池化技术 事先准备好一些资源,有需要就给

        程序的运行本质就是利用系统资源去完成任务,所以需要优化CPU资源的实验

        线程池、JDBC连接池、内存池、对象池 需要设置核心参数

        线程池的好处:降低资源的消耗、提高响应速度、方便管理

        即 线程复用、控制最大并发数、管理线程

        Executors

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I8JFfJ5g-1648363882203)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325171243391.png)]

        三大方法:Single:单一线程, Fixed:固定的数量,Cached:容量可伸缩 七大参数
            public ThreadPoolExecutor(int corePoolSize,
                                      int maximumPoolSize,
                                      long keepAliveTime,//超时释放
                                      TimeUnit unit, //超时单位
                                      BlockingQueue workQueue,//阻塞队列
                                      ThreadFactory threadFactory,//线程工厂,创建线程,一般不用动
                                      RejectedExecutionHandler handler//拒绝策略) {
                if (corePoolSize < 0 ||
                    maximumPoolSize <= 0 ||
                    maximumPoolSize < corePoolSize ||
                    keepAliveTime < 0)
                    throw new IllegalArgumentException();
                if (workQueue == null || threadFactory == null || handler == null)
                    throw new NullPointerException();
                this.corePoolSize = corePoolSize;
                this.maximumPoolSize = maximumPoolSize;
                this.workQueue = workQueue;
                this.keepAliveTime = unit.toNanos(keepAliveTime);
                this.threadFactory = threadFactory;
                this.handler = handler;
            }
        

        阿里巴巴规范

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hruPWlcK-1648363882204)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325173322451.png)]

        手动创建线程池

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hvviqhgm-1648363882204)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325175547980.png)]

        DiscardOldestPolicy队列满了,尝试去和最早的竞争,不会抛出异常

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LwyIk8lG-1648363882205)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325181458914.png)]

        CPU密集型和IO密集型

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-te2Pk8DV-1648363882205)(C:Users86159AppDataRoamingTyporatypora-user-imagesimage-20220325204358011.png)]

              throw new IllegalArgumentException();
          if (workQueue == null || threadFactory == null || handler == null)
              throw new NullPointerException();
          this.corePoolSize = corePoolSize;
          this.maximumPoolSize = maximumPoolSize;
          this.workQueue = workQueue;
          this.keepAliveTime = unit.tonanos(keepAliveTime);
          this.threadFactory = threadFactory;
          this.handler = handler;
          
          }
        阿里巴巴规范
        
        [外链图片转存中...(img-hruPWlcK-1648363882204)]
        
        ##### 手动创建线程池
        
        [外链图片转存中...(img-Hvviqhgm-1648363882204)]
        
        ==DiscardOldestPolicy队列满了,尝试去和最早的竞争,不会抛出异常==
        
        [外链图片转存中...(img-LwyIk8lG-1648363882205)]
        
        #### CPU密集型和IO密集型
        
        [外链图片转存中...(img-te2Pk8DV-1648363882205)]
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        转载请注明:文章转载自 www.mshxw.com
        本文地址:https://www.mshxw.com/it/782038.html
        我们一直用心在做
        关于我们 文章归档 网站地图 联系我们

        版权所有 (c)2021-2022 MSHXW.COM

        ICP备案号:晋ICP备2021003244-6号