00.Java基-集合:IO:JUC

八大基本类型

byte short int long float double boolean char

包装类

Byte Short Integer Long Float Double Boolean Character

java运行机制

编译 .java的源文件,在用编译期javac,将源程序编译程 .class字节码文件,用虚拟机(解释器)解释执行

javac Hello.java java Hello

方法重载

变量个数与类型不同

垃圾回收机制

堆中对象的管理: 对象空间创建new和释放null

  • 垃圾回收原理
      1. 引用次数法
        • 记录对象引用次数(0表示无用对象)
      1. 引用可达法(搜索算法)

对象创建过程

  1. 分配对象空间、成员变量初始化0/null @1
  2. 执行属性值显示初始化 @2
  3. 执行构造器 @3
  4. 返回对象地址给相关变量 @4

内存空间返回 与 内存空间初始化 之间顺序是可以任意的(—>指令重排)

this

  • this的本质是创建的对象的地址
  • 构造器不是用来创建对象的
  • 构造方法调用其他构造方法: this要放第一行

集合 1

在这里插入图片描述

Collection体系 2

List有序集合 3

ArrayList、LinkedList 4
  • 底层结构
    • ArrayList底层是基于数组实现的,内存地址连续—>查找快
    • Linked是基于链表实现的(运行NULL)
  • 扩容方式
    • ArrayList达到扩容情况,原数据+扩容数组–>涉及扩容与移动(增删慢,查询快)
    • LinkedList 添加、删除节点—>节点–>(增删快,查询慢)
  • other
    • 都实现了List接口,但LinkedList额外实现了Deque接口,所以LinkedList也可以做双端队列
Vector 4

底层数组+synchronized---->效率很低

Set 3

HashSet 4
  • HashSet底层还是HashMap—>可以null
    • map.put(e, PRESENT)==null;插入的本质就是只关心key,value就是一个常亮
  • 无序、不重复(先判断hashcode、在equals判重)
LinkedHashSet 4
  • 有序、线程不安全
TreeSet 4
  • 底层红黑树
  • 自然排序—>实现了Comparable接口

Map体系 2

遍历方式:

​ (1)keySet();遍历key

​ (2)迭代器entrySet().iterator()

​ (3)entrySet()效率高

​ (4)values()只能遍历value

HashMap 3

JDK1.7 HashMap–>数组+链表(链表是为了解决hash冲突)

  • 内部结构:哈希表,不同步,允许null做key-value
  1. hash冲突,会先遍历链表,然后插入链头—>允许key、value为null

    • 通过key与哈希算法与与运算得到数组下标
    • 将key、value封装成Entry对象(1.7Entry,1.8Node对象)
  2. key相同,value便覆盖

  3. 扩容(多线程)可能导致链表循环等并发修改异常

    1. hash种子,是为了让hash值更散列
    2. modcount—>版本号
      1. 遍历的时候删除(可能会异常),通过迭代器去删除,让迭代器的modcount与hashmap的迭代器同步,避免异常
    • 扩容方式
      1. JDK1.7,先判断是否扩容,然后生成Entry对象,头插法插入链表
      2. JDK1.8,先判断当前位置上一个Node类型,是红黑树Node还是链表Node
        • 若红黑树Node,将key、value封装未一个红黑树添加到红黑树当中(判断是否存在当前key,存在则更新value)
        • 若链表Node,将key、value封装成链表Node尾插法插入林彪
          • 插入过程中,先遍历链表,若存在key,更新value
          • 插入到链表后,如果当前链表节点>8,链表转为红黑树
          • key、value封装成Node插入到链表或红黑树后,判断是否扩容

JDK1.7 HashMap–>数组+红黑树

key值<=8时是:数组+链表,key>8时是:数组+红黑树

HashTabale 3

  • 内部结构:哈希表,同步,不允许null做key-value

TreeMap 3

  • 内部结构:二叉树,不同步,允许null做key-value

IO

4大IO抽象类

InputStream/OutputStream字节流、Reader/Writer字符流

  1. 操作数据源/数据目的(读/写)

源: InputStream Reader

目的: OutputStream Writer

  1. 数据是文本还是字节

源:

​ 字节:InputStream

​ 文本:Reader

目的:

​ 字节:OutputStream

​ 文本:Writer

  1. 数据所在设备

    源设备

    ​ 硬盘:文件File开头

    ​ 内存:数组、字符串

    ​ 键盘:System.in

    ​ 网络:Socket

    目的设备

    ​ 硬盘:文件File开头

    ​ 内存:数组、字符串

    ​ 键盘:System.out

    ​ 网络:Socket

  2. 额外功能

转换流:InputStreamReader OutputStreamWriter

高效(缓冲流): Bufferedxxx

对象序列化:bjectInputStream、ObjectOutputStream

数据输出格式: 打印流 PrintStream PrintWriter

  • 字节流
    在这里插入图片描述

    • FileOutputStream有单参和两参(间接/直接路径,是否追加)
  • 字符流Reader、Writer
    在这里插入图片描述

  • InputStreamReader/Writer有单参和两参(间接/直接路径,编码格式)

  • close和flush

    flush 先刷新缓冲区,流对象可以继续使用

    close 先刷新缓冲区,然后释放资源

  • ObjectOutputStream/ObjectInputStream

    • 对象必须实现Serializable接口
    • 不需要序列化的属性,用transient修饰

Properties属性类

public void load(InputStream inStream)从输入流中读取属性列表(键和元素对)
getProperty(String key)   在此属性列表中搜索具有指定键的属性
setProperty(String key, String value)

异常 1

异常体系 2

在这里插入图片描述

Error:程序中无法处理的错误

Exception:程序本身可以捕获,并可以处理的异常

​ 运行时异常:(非受控异常)(不需要预处理,通过规范的代码可以避免产生这种异常)

​ 一般性异常:(受控异常)(这种异常必须显示处理,否则无法编译通过)

异常处理

  • 抛出异常throw,throws
    • throw抛出一个异常对象,并将异常对象传递给调用者,结束当前方法执行:throw new 异常名(参数);
    • 声明抛出异常throws:运用于方法声明上,表示当前方法不处理异常,而是提醒方法调用者处理异常
  • 捕获异常try,catch,finally(异常的捕获,一般按照由大到小顺序,先捕获子异常、在捕获父异常,否则编译错误)

getMessge()和printStackTrace()

  • 获取异常描述信息
    • getMessage()方法,通常用于打印日志
  • 获取异常的堆栈信息
    • printStackTrace(),适合程序调试阶段
  • 面基:

Java异常处理机制的理解

Java对异常进行了分类,不同类型的异常分别用不同的Java类表示,所有异常的根类为 java.lang.ThrowableThrowable下面又派生了两个子类:ErrorExceptionError: 表示应用程序本身无法克服和恢复的一种严重问题。

Exception: 表示程序还能够克服和恢复的问题,其中又分为系统异常和普通异常
系统异常
	系统异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者让软件死掉,例如,数组下标越界,空指针异常、类转换异常。

普通异常
	普通异常是运行环境的变化或异常所导致的问题,是用户能够克服的问题,例如,网络断线,硬盘空间不够,发生这样的异常后,程序不应该死掉。
  
普通异常必须trycatchthrows抛给上层调用者(checked异常)
系统异常可以不处理(unecked异常)

JUC 1

线程、进程

  • 进程: 运行的程序,至少一个线程
  • 线程: 轻量级进程
  • Java程序,至少主线程+gc线程

并发、并行

  • 并发: 同时做(同一时间)
  • 并行: 一起做(轮流)

JUC核心包

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

线程状态

new新生、RUNNABLE运行、BLOCKED阻塞、WATING死等待、TIMED_WATING超时等待、

//创建线程new、就绪状态、阻塞状态B、运行状态、dead

wait、sleep

  • 来自不同类: wait–>Object sleep–>Thread
  • 锁释放: wait()可以释放 sleep()不会释放锁
  • wait必须在同步代码块 sleep任意地方睡
  • wait不需捕获异常 sleep要捕获异常

synchronized、Lock

  • synchronizd

  • static情况锁类Class模板,非static情况锁对象

  • Lock

    自定义锁的内容

线程休眠—>sleep时间到达后线程进入就绪状态、且并不会释放锁

线程礼让:让正在运行的线程暂停,但不阻塞,运行状态转为就绪状态(CPU重新调度)

强制线程执行:join(),当前线程执行完后,其他线程才可以执行(阻塞其他线程)、线程状态getState();

线程优先级:线程之间可以设置优先级来进行优先执行与否,但不一定成功

用户线程、守护线程(setDaemon(true): 虚拟机,确保了用户线程必须执行完毕,不确保守护线程

线程协作(通信)

    1. 管程法
    • 通过缓冲区(容器),对缓冲区适当调用wait() notifyAll(),进行协作
    1. 信号灯
    • 线程之间,设置一个标志位,通过标志位状态,去决定线程运行状态与操作

volatile 2

  • Java虚拟机提供轻量级
    同步机制

  • 保证可见性

    • 一个线程修改共享值写会主存后,其他线程立刻知道自己缓存的共享值失效,需重新读入
  • 不保证原子性

    • 操作不能保证原子性(一致),可能导致值覆盖—>写丢失

      • 工作内存与主内存同步延迟现象导致的可见性问题
    • 解决方案:

      • synchronized、Lock锁
      • 原子包装类Atomic/(Integre/Double)
  • 有序性:禁止指令重排(重排->优化没有依赖性的操作)

    • 指令重排: 禁止指令重排,避免多线程情况下程序乱序执行现象

      • 源代码 --> 编译期优化重排 --> 指令并行重排 --> 内存系统重排 --> 最终执行指令
      • 指令重排,须考虑指令之间的 数据依赖性
    • 内存屏障 <— volatile

  • 修饰关键字: 增加了主线程和线程之间的可见性,只要一个线程修改了内存中的值,其他线程也能马上感知


JMM 内存模型 2

  • 是一种规范

  • 同步的规范

    • 线程解锁前:必须把共享变量刷回主存

    • 线程加锁前:读取主内变量到工作内存—>线程通信:拷贝到工作内存<–>写回主存

    • JMM内模型可见性:主内存的值,写入进程更改后(写回主存),其他线程也会知道更改后的值,并重新得到更改的值

  • JMM三大特性

    • 可见性
    • 原子性
    • 有序性
  • 缓存一致性

    • MESI

      CPU写数据时,如果操作的变量是共享变量,会发出信号通知其他CPU将该内存变量的缓存行设置为无效,其他CPU读取这个变量时,会发现自己缓存改变量的缓存行是无效的,变回从内存中重新读取。主内存值修改了,其他内存值也会马上得到通知
      在这里插入图片描述
      在这里插入图片描述

CAS底层原理:Compare-And-Swap比较并替换 2

  • 判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程原子的
  • CAS是一条CPU的原子指令,不会造成数据不一致问题CAS是下线程安全的
  • CAS是不加锁的,原子性的(本质是比较当前工作内存的值和主存的值,如果相同执行操作,否则一直比较直到主存和工作内存值一致为止)
  • CAS实际上调用了Unsafe类中的本地方法

CAS导致的ABA问题

获取主内存值,到写回主存的过程中,可能该值已经被修改了N次,但是最终修改回原来的值而已 可能线程CAS操作成功,但是可能可能过程是有问题的

  • 解决ABA问题方法:
    • 时间戳原子引用AtomicStampedReference,通过版本号来限制ABA问题
    • LongAdder(CAS机制优化)
      • CAS底层是通过自旋,不断尝试修改值–>耗性能—> LongAdder引入

JUC下Collection 2

并发情况下,一般的集合的操作可能会出现并发修改异常

  • 解决方法
    • 方法一:Vector
      • 本质是在方法上加了synchronized锁–>一次只有线程可以操作–>线程安全、并发性能低
    • 方法二:Collctions.synchronized()
      • 本质是给传入的集合外包装一层 同步机制
    • 方法三:JUC 提供的类CopyOnWrite(List/Set),ConcurrentHashMap
      • 写时复制–>读写分离
      • 写时复制容器,写完指向当前容器,读写使用不同容器

2

  1. 公平锁、非公平锁
  • 公平锁: FIFO先来先服务—>队列
  • 非公平锁: (上来就尝试占有锁,不成功就类似公平锁方式)可插队–>synchronized也是非公平锁
  • Lock lock = new ReentrantLock(true/false); 默认false非公平锁、true公平锁
  • 非公平锁性能(吞吐量)比公平锁大
  1. 可重入锁(递归锁)—>避免死锁
  • 线程可以进入任何一个它已经拥有的锁所同步的代码块
  • ReentrantLock、Synchronized就是可重入锁
  1. 自旋锁: spinlock
  • 尝试获取锁的线程不会立刻阻塞,采用循环的方式不断获取锁–>避免上下文切换的消耗 <-- 循环消耗CPU
  • CAS底层就是自旋锁
  1. 读锁、写锁(独占锁、共享锁)
ReentrantReadWriteLock //读写锁
lock.writeLock().lock(); lock.writeLock().unlock();
lock.readLock().lock();  lock.readLock().unlock();		
  1. Synchronized无法禁止指令重排,但可以保证有序性
  1. 死锁

死锁: 线程之间抱着对方需要的资源不放

  • 互斥条件:一个资源只能被一个线程使用
  • 请求与保持: 一个线程对已有的资源不放,去请求其他资源被阻塞
  • 不剥夺: 进程已获得资源,未释放前,不能强行剥夺
  • 循环等待: 进程之间线程头尾相接循环等待资源

JUC辅助类 2

CountDownLatch

  • 让一些线程阻塞直到另一些线程完成一系列操作才被唤醒

countDownLatch.countDown();

countDownLatch.await();当线程到达预订好的上限时,才开始执行await之后的代码,否则一直死等

CyclicBarrier

  • 开始为0,做加法,直到加到某个值的时侯执行让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障后,屏障才会开门,所有被阻塞的线程继续运行

cyclicBarrier.await(); 线程进入屏障

Semaphore 信号量

  • 用于资源互斥使用与并发线程数的控制
  • acquire();信号量-1
  • release(); 信号量释放

阻塞队列、非阻塞队列 2

BlockingQueue(阻塞队列)接口—>Queue—>Collection
AbstractQueue(非阻塞队列)—>Queue—>Collection
在这里插入图片描述

阻塞队列 BlockingQueue

阻塞队列为空,获取队列元素->阻塞 阻塞队列满,添加元素->阻塞

ArrayBlockQueue数组组成的有界阻塞队列 LinkedBlockingQueue链表组成有界阻塞队列(默认大小Integer.MAX_VALUE相当于无界)

SynchronousQueue 不存储元素的阻塞队列(单个元素的队列)(每一个put操作,都伴随一个take操作)

PriorityBlockQueue支持优先级的无界阻塞队列 DelayQueue 优先级延迟无界阻塞队列

LinkedTransferQueue链表无界阻塞队列 LinkedBlockingDeque链表组成双向阻塞队列

方法类型抛出异常特殊值阻塞超时
插入add(e)队满插入报异常offer(e)插入成功true,失败falseput(e)队满死等插入offer(e,time,unit)
移除remove()队空移除报异常poll()成功返回队首,否则返回空take()队空死等移除poll(time,unit)
检查element()peek()--

Synchronized与Lock区别

  1. Synchronized无需手动释放,代码块执行完后自动解锁,Lock需手动加锁、释放锁

  2. synchronized不可中断,ReentrantLock可以中断与超时方法trylock(long timeout,TimeUnit unit);

  3. synchronized非公平锁、Lock通过构造函数传递布尔值默认非公平锁,true为公平锁

  4. Lock可以绑定多个条件,实现对线程分组和精准唤醒–>可以实现线程之间的循环

    Synchronized只能随机唤醒和全部唤醒

  5. synchronized是JVM层面–关键字,Lock是API层面–具体类

线程池 2

  • 线程实现方式
    • 实例化Thread类
    • 实现Runnable接口
    • 实现Callable接口—>有返回值(通过FutureTask将Callable实现类携带到Thread去启动)
    • 线程池获取—>线程复用、控制最大并发数(类似于JDBC)、减少上下文开销

创建线程池方式

  • Executors.newFixedThreadPool(int i); 定长线程池 <–队列太长,可能堆积大量请求

  • Executor.newSingleThreadExecutor();单线程池 <–队列太长,可能堆积大量请求

  • Executors.newCacheThreadPool();可扩容线程池<–队列长度Integer.MAX_VALUE线程上限太大可能导致OOM

  • Executor.newScheduledThreadPool(int corePoolSize);定时、周期性线程池<—队列长度Integer.MAX_VALUE 线程上限太大

  • 线程池参数

    public ThreadPoolExecutor(
      int corePoolSize, //核心线程数量
      int maximumPoolSize, //最大线程数量
      long keepAliveTime, //空闲线程存活时间
      TimeUnit unit, //存活时间单位
      BlockingQueue<Runnable> workQueue, //任务队列:LinkedBlockingQueue阻塞队列和Synchronized同步阻塞队列
      ThreadFactory threadFactory, //线程工厂
      RejectedExecutionHandler handler //拒绝策略:队列满了且线程大于最大线程数-->开始拒绝策略
    )
    
  • 拒绝策略

    • AbortPolicy: 默认,抛出异常,阻止系统正常运行
    • DiscardPolicy: 直接丢弃
    • CallerRunsPolicy: 将任务回退给调用者
    • DiscardOldestPolicy: 抛弃队列中等待最久的任务

线程池作用

  • 减少创建、销毁线程所消耗的时间

线程池参数设置:分配corePoolSize、maximumPoolSize

  • CPU密集型: 所有的线程都用于任务
  • IO密集型: 给出一半的线程用于IO操作
//线程池运行过程
1.创建线程池,等待提交过来的任务
2.调用execute()添加线程任务
	1.如果正在运行的线程数量小于`核心线程`,马上创建线程运行当前任务
	2.如果正在运行的新城数量大于等于`核心线程`,将任务放入队列中
	3.队列满了,运行的线程数量小于`最大线程数量`,创建非核心线程去运行当前任务
	4.队列满了,运行的线程数量大于等于`最大线程数量`,线程池饱和,启动拒绝策略
3.线程完成任务,从队列去任务,去执行
4.非核心线程空闲一定时间,线程停掉

项目排查JVM问题 2

  • 使用jmap查看jvm中各个区域的使用情况
  • jstack查看线程的运行情况(那些线程阻塞、出现死锁)
  • 通过jstat查看垃圾回收的情况,特别是fullgc,如果fullgc频繁,就得调优了
  • 找到占用CPU最多的线程,定位到具体方法,优化某个方法执行,看能否避免对象创建,从而节省内存

死锁排查 2

jps -l 找到一直运行的线程

jstack 进程号 查看堆栈信息

其他 1

序列化

  • 序列化必须实现Serializable接口
  • 变量被transient修饰,变量不会被序列化
  • static修饰的变量不参与序列化,无论静态变量是否被transient修饰
  • final变量参与序列化、final transient同时修饰:不会序列化
  • 一般要自定义SerialversionUID,避免了修改原来的pojo,导致反序列化失败

static

  • static的意义:创建独立于具体实例对象的域变量或方法(没有创建对象,也能使用属性和调用方法),在内存中只有一份,在类加载过程中,JVM分配一次内存空间
  • 静态代码块:类初次加载时,按static块顺序来执行每个static块且只执行一次
  • 静态方法:不属于实例对象,自然就用不上this关键字了(静态访问静态、非静态可访问非静态+静态)

String底层

实现了:Serializable可序列化接口、Comparable<String>比较大小接口、CharSequence常用方法的接口

String类是final修饰的,数组(jkd8前是字符数组:占两个字节,jdk9后就是byte数组,占一个字节,StringBuffer和StringBuilder也是一样)

StringBuffer线程安全,执行效率低、StringBuilder线程不安全,执行效率高


  • String不可变,变的只是引用的对象,原来的对象依然存在内存中

  • String的value引用的内存区域存储的值,无法改变,但可以改变value引用

  • String可以通过反射的方式,不改变value的引用,而改变value引用下的值(通过反射,先拿到String的value字段,然后改变访问权限,然后设置value字段的值)–通过反射可以修改不可变的对象。

  • String字符串的拼接

    • 常量与常量的拼接,实在编译期
    • 只要有一个是变量(就是new String()就会创建新空间),变量拼接的原理是StringBulider(jdk5之后,之前用StringBuffer)
  • intern()方法

    • 底层调用了本地方法
    • 作用是:当前字符串是否在常量池中存在
      • 存在:直接返回地址
      • 不存在:将堆中字符串的地址复制到字符串常量池中,这样常量池就有了该字符串地址引用
    • new String(“sb”)实际上是创建了两个对象
      • 一个是在堆中创建的对象
      • 一个实在堆中字符串常量池中创建
      • 这两个对象内容一样,但地址不一样

final

  • 修饰类:该类无法继承(编译报错)

  • 修饰方法:不可以重写(编译报错)

  • 修饰变量:

    • 基本数据类型:初始化后,无法改变

      • 成员变量:定义时或构造器中,初始化赋值(编译错误)

      • 局部变量:在使用之前初始化即可

        String a = "Hello1";
        final String b = "Hello";					
        String c = "Hello";
        b1 = b + 1;
        c1 = c + 1;
        System.out.println(a==b1);  //true
        System.out.println(a==c1);	//true
        

        final修饰的变量,编译期就已经知道,所以遇到final修饰的值,直接就会替换成常量值了,而变量只有在运行期间才能确定

    • 引用类型:初始化后,无法改变引用

函数式接口

四大函数式接口:简化编程模型
lambda表达式、链式编程、函数式接口、Stream流式计算

  • 函数式接口interface Function<T, R>
    • 只有一个方法的接口
    • @FunctionalInterface
      函数型接口,可用lambda表达式简化
  • 断定型接口interface Predicate
    • 只有一个输入参数,返回值只能 布尔值
  • 消费型接口interface Consumer
    • 只有一个输入参数,没有返回值
  • 供给型接口interface Supplier
    • 没有参数,只有返回值

Stream流式计算
interface Stream
所有的集合都有一个stream()方法,将集合变成流对象

Lamda表达式

函数式接口—>只包含一个抽象方法,甚至可以去掉参数类型


值传递、引用传递

八种基本数据类型,在栈里面分配内存,属于值传递

引用类型,在存储在堆区,属于引用传递

栈管运行,堆管存储

正则表达式

[a-zA-Z] 范围限定

长度限定:{}

[a-z]{5} 长度5

[a-z]{2,8} 长度2-8

[a-z]{2,} 长度最少2

长度限定符号

预定义符号来完成长度限定

? 零次或一次,等价于{0,1}

+ 一次或多次,等价于{1,}

*零次或多次,等价于{0,}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值