# 前言

  1. IO:

    a. 转换流:进行字符和字节之间的转换

    b. 系统流:都是System类中的对象,本质上是字节流

    c. 打印流:只有输出没有输入,提供了便捷的打印和换行的操作

    d. 合并流:将多个字节输入流合并成一个字节输入流;在合并的时候需要将这多个字节流放入一个Enumeration中

    e. 序列化/反序列化:

    i.  序列化 - 将对象转化为字节数组
    
    ii. 反序列化 - 将字节数组还原回对象
    
    iii. 一个接口 - Serializable,两个关键字 - static/transient,一个属性 - serialVersionUID
    
    iv. 允许对集合进行整体的序列化
    
  2. RandomAccessFile:

    a. 双向流,可以对文件进行读写操作

    b. 在操作文件的时候是把文件看做一个大型的字节数组

    c. 在使用的时候需要指定模式

  3. Properties:

    a. 是一个可以持久化的映射

    b. 键和值默认都是String

    c. 在持久化的时候要求数据必须持久化到properties文件中

    d. properties文件的编码默认是西欧编码,所以如果存入中文会自动转化为对应的utf-16的编码

    e. 经常作为配置文件使用

  4. 断言:

    a. 格式:assert 判断条件 : 提示信息;

    b. 根据已知条件来对结果进行预判

    c. 在Java中,断言默认是不开启的,所以需要手动添加参数-ea

  5. 单元测试:

    a. 在使用的时候需要导入测试库Junit4

    b. 三无:无参、无返回值、非静态

    c. @Test, @Before, @After

  6. 静态导包:

    a. 格式:import static 包名.类名.静态方法名;

    b. 优点:优先加载指定的静态方法,来提高运行效率

    c. 缺点:书写麻烦、可读性不强、方法签名一致的方法

# 线程

一、概述

  1. 进程:当前操作系统执行的任务

  2. 一般而言,现在操作系统都是多进程的

  3. 线程:进程中的子任务

  4. 在实际应用中,都是多线程的场景

  5. 线程本身是在CPU上执行,CPU的每一个核在同一时刻内只能执行一个线程,但是CPU在底层会对线程进行快速的轮询切换

  6. 每一个进程中至少包含1个线程

  7. 线程在执行任务的过程大概可以分为2大块:

    a. 在CPU上执行

    b. 和计算机的硬件进行交互。当线程和硬件进行交互(例如读取文件)是不占用CPU的

  8. 多线程的意义:提高CPU利用率。理论上,当线程个数足够多的时候,

CPU的利用率是能够到达100%

  1. 主函数所在的类默认是一个单独的线程

二、定义线程

  1. 继承Thread,重写run方法,将要执行的逻辑放到run方法中,然后创建 线程对象调用start方法来开启线程

  2. 实现Runnable,重写run方法,然后利用Runnable对象来构建Thread对象 调用start方法来启动线程

  3. 实现Callable<T>,重写call方法 --- 在现阶段仅作了解

三、多线程的并发安全问题

  1. 线程之间是相互抢占执行,而且抢占是发生在线程执行的每一步

  2. 由于线程的抢占而导致出现了不合理的数据的现象 - 多线程的并发安全问题

四、线程中的锁机制

  1. 为了解决线程并发问题,引入了synchronized代码块 - 同步代码块

  2. 同步代码块需要一个锁对象

  3. 锁对象:要求被当前的所有线程都认识 - 共享资源、方法区中的资源、this

  4. this作为锁对象的时候,要求利用同一个Runnable对象来构建不同的Thread对象

  5. 同步:在同一时刻内资源/逻辑只被一个线程占用/执行

  6. 异步:在同一时刻内资源/逻辑可以被多个线程抢占使用

  7. 同步一定安全,不安全一定是异步

  8. 由于多个线程之间的锁形成了嵌套而导致代码无法继续允许,这种现象 称之为死锁

  9. 现阶段,只能尽量避免死锁。实际开发中,会做死锁的检验;如果真的 出现死锁,会根据线程的优先级打破其中一个或者多个锁

五、线程的优先级

  1. 将线程的优先级分为1-10一共十个等级

  2. 理论上,数字越大优先级越高,那么该线程能抢到资源的概率就越大

  3. 实际上,相邻的两个优先级之间的差别非常不明显;如果想要相对明显

一点,至少要相差5个优先级

六、等待唤醒机制

  1. 利用标记位以及wait、notify、notifyAll方法来调节线程之间的执行顺序

  2. wait、notify、notifyAll和锁相关,用哪个对象作为锁对象使用,那么就用该锁对象来调用wait、notify

七、线程的状态

八、守护线程

  1. 守护其他的线程,只要被守护的线程结束,那么守护线程就会随之结束

  2. 一个线程要么是守护线程要么是被守护的线程

  3. 守护线程可以守护其他的守护线程

  4. 在Java中,最常见的一个守护线程是GC

总结:sleep和wait

  1. sleep:在使用的时候需要指定休眠时间,单位是毫秒,到点自然醒。在无锁状态下,会释放CPU;在有锁状态下,不释放CPU的。sleep方法是 设计在了Thread类上,并且是一个静态方法

  2. wait:可以指定等待时间也可以不指定。如果不指定等待时间则需要被 唤醒。wait必须结合锁来使用,当线程在wait的时候会释放锁。wait方法是设计在了Object类上

总结:线程产生的场景

  1. 系统自启

  2. 用户请求

  3. 线程之间的启动

总结:线程结束的场景

  1. 寿终正寝:线程自然结束

  2. 他杀:被其他线程kill

  3. 意外:线程因为报错崩溃而退出

扩展:方法区和线程的关系

  1. 类是存储在方法区中,方法区被所有的线程共享的空间

  2. 每一个线程独有一个栈内存

单例模式

一、概述

  1. 在全局过程中只存在一个对象

  2. 饿汉式:在定义对象的时候将这个对象进行了初始化

  3. 懒汉式:将对象的初始化过程推后

  4. 懒汉式相对饿汉式而言,将对象的初始化过程推后,提高了类的加载速率,但是存在线程安全问题;饿汉式是线程安全的

扩展作业:了解单例模式的七种方式

Last Updated: 11/18/2022, 10:55:14 AM