Java(3)

File

  1. File 仅仅封装一个路径名,这个路径可以存在也可以不存在
    • 构造方法
      1. File(String pathName) pathName指定路径,可以是文件也可以是文件夹
      2. File(String parent, String child) parent + child 组成文件夹,两个参数中间的分隔符会自动加上,在任一参数下加分隔符也都可以
      3. File(File parent, String child) 父路径是一个File对象
    • 常用方法
      1. 创建功能
        • boolean createNewFile() 创建一个新的空文件
          1. 如果文件存在,那么创建失败返回false
          2. 如果文件不存在,那么创建成功返回true
          3. 不管创建的目标有没有后缀,都只会创建文件
        • boolean mkdir() 创建一个新的空文件夹
          1. 必须保证父文件夹存在的情况下才能创建单级文件夹
          2. 不管创建的目标有没有后缀,都只会创建文件夹
        • boolean mkdirs() 创建一个多级的空文件夹
          1. 没有父文件夹,就会把父文件夹也创建出来
          2. 不管创建的目标有没有后缀,都只会创建文件夹
      2. 删除方法
        • booelan delete() 文件和文件夹都可以删除
          1. 不走回收站
          2. 文件直接删除,文件夹只能删除空文件夹
          3. 文件夹有内容则删除失败
      3. 判断和获取功能
        • boolean isDirectory() 判断是不是文件夹
        • boolean isFile() 判断是不是文件
        • boolean exists() 判断是否存在
        • String getName() 获取文件(文件名和后缀)或文件夹的名称
        • String getAbsolutePath() 获取File对象的绝对路径名字符串
        • String getPath() == toString() 构造器传入的路径字符串
        • File[] listFiles() 返回File文件夹中的所有子文件或目录的File数组描述
          1. 当调用对象不存在时,返回null
          2. 当调用对象是一个文件时,返回null
          3. 当调用对象是一个空文件夹时,返回一个长度为0的数组
          4. 当调用对象是一个有内容的文件夹时,返回子文件和文件夹(包括隐藏)
          5. 当调用对象是一个需要权限才能进入的文件夹时,返回null
        • public String[] list() 返回File文件夹中的所有子文件(隐藏的也在)或目录的Stirng数组描述,仅仅自己这层,孙子文件或文件夹不包括在内
        • public File[] listFiles(FileFilter filter) 根据过滤条件返回遍历内容
          1. java.io.FileFilter 接口,过滤文件的接口
          2. public boolean accept(File pathname)
            • 参数pathname: 当前正在遍历的File对象,可能是文件也可能是文件夹
        • public File[] listFiles(FilenameFilter filter) 根据过滤条件返回遍历内容
          1. java.io.FilenameFilter 接口,过滤文件的接口
          2. public boolean accept(File dir, String name)
            • 参数dir:当前正在遍历的File对象的父目录,也就是构造方法中传进去的File对象,也是调用listFile的那个对象本身
            • 参数name:当前正在遍历的File对象的名字

字节流

  1. 所有的文件数据,都可以用字节流传输
  2. 字节输出流(OutputStream)
    • java.io.OutputStream 抽象类,是所有字节输出流实现类的超类
      1. 基本方法
        • void close() 关闭流,关闭资源
        • void flush() 刷新此输出流并强制所有缓冲的输出字节被写出
        • void write(byte[] b) 将b字节写入到输出流
        • void write(byte[] b, int off, int len) 将b字节从off开始,写入len个长度到输出流
          1. off,从0开始
          2. len,off位置的那个字节是第一个,一直数到len结束
        • void write(int i) 将i转byte后,写入一个字节到输出流
    • java.io.FileoutputStream extends OutputStream 文件字节输出流,把内存中的数据写到硬盘的文件中
      1. 构造方法,创建一个文件输出流就会创建对应的文件
        • FileOutputStream(String fileName) 创建一个向指定名称的文件中写入数据的文件输出流
        • FileOutputStream(File file) 创建一个向指定file对象的文件中写入数据的文件输出流
        • FileOutputStream(String fileName, boolean append) 是否续写
        • FileOutputStream(File file, boolean append) 是否续写
      2. 基本使用
        • 一次写入多个字节
          1. void write(byte[] b)
          2. void write(byte[] b, int off, int len)
          3. 如果第一个字节是整数,显示的时候会查询ASCII表
          4. 如果第一个字节是负数,那第一个字节就会和第二个字节组成中文显示,查询系统默认编码表(GBK)(UTF-8三个字节表示一个中文)
        • 一次写入一个字节
          1. void write(int i) 写入后,记事本会把每个字节翻译成字符显示
        • 写字符串:把字符串getBytes()转换为byte[]即可
        • 写换行
          1. win: \r\n
          2. linux: \n
          3. mac: \r
  3. 字节输入流(InoutStream)
    • java.io.inputStream 抽象类,是所有字节输入流实现类的超类
      1. 基本方法
        • void close() 关闭流,关闭资源
        • abstract int read() 从输入流读取数据一个字节
        • int read(byte[] b) 从输入流中读取多个字节存放到b中,返回读取到的有效字节数
    • java.io.FileInputStream extends InputStream 文件字节输入流,把文件中的数据读取到内存中
      1. 构造方法
        • FileInputStream(File file) 创建一个向指定file对象的文件中读取数据的文件输入流
        • FileInputStream(String fileName) 创建一个向指定名称的文件中读取数据的文件输入流
      2. 基本使用
        • 读取一个字节:int read() 读取到文件末尾会返回-1
        • 读取多个字节:int read(byte[] b) 读取到文件末尾会返回-1

String类中的编码和节码问题

  1. 编码
    • byte[] getBytes() 使用平台的默认字符集将该String编码为字节存储到数组中
    • byte[] gteBytes(String charsetName) 指定编码集的编码
  2. 解码
    • String(byte[] bytes) 通过平台的默认字符集解码指定的字节数组来构造新的String
    • String(byte[] bytes, String charsetName) 指定编码集的解码

字符流

  1. 使用字节流读取文本文件时,如果遇到中文字符,正好把一个中文的多个字节拆开读了,那么中文可能会出问题。所以Java提供了字符流专门用于处理文本文件。同字节流一样与一次读取一个字节,但是碰到负数时会把整个字符的所有字节都读出来
  2. 字符输入流(Reader)
    • java.io.Reader 抽象类,是所有字符输入流实现类的超类
      1. 基本方法
        • public void close() 关闭流,关闭资源
        • public int read() 从输入流中读取一个字符
        • public int read(char[] cbuf) 从输入流中读取多个字符放到cbuf中,返回读取到的有效字符数
    • java.io.FileReader extends InputStreamReader extends Reader 文件字符输入流
      1. 构造方法
        • FileReader(String fileName) 创建一个向指定file对象的文件中读取数据的文件输入流
        • FileReader(File file) 创建一个向指定名称的文件中读取数据的文件输入流
      2. 基本使用
        • 读取一个字符:int read() 读取到文件末尾会返回-1
        • 读取多个字符:int read(char[] cbuf) 读取到文件末尾会返回-1
  3. 字符输出流(Writer)
    • java.io.Writer 抽象类,是所有字符输出流实现类的超类
      1. 基本方法
        • public void close() 关闭流,关闭资源
        • public void flush() 刷新此输出流并强制所有缓冲的输出字符被写出
        • public void write(char[] cbuf) 将c字符写入到输出流
        • public void write(char[] cbuf, int off, int len) 将c字符从off开始,写入len个长度到输出流
          1. off,从0开始
          2. len,off位置的那个字节是第一个,一直数到len结束
        • public void write(int c) 将i转char后,写入一个字符到输出流
        • public void write(String str) 写入字符串
        • public void write(String str, int off, int len) 写入字符串的一部分
    • java.io.FileWriter extends OutputStreamWriter extends Writer 文件字符输出流
      1. 构造方法,创建一个文件输出流就会创建对应的文件
        • FileWriter(String fileName) 创建一个向指定名称的文件中写入数据的文件输出流
        • FileWriter(File file) 创建一个向指定file对象的文件中写入数据的文件输出流
        • FileWriter(String fileName, boolean append) 是否续写
        • FileWriter(File file, boolean append) 是否续写
      2. 基本使用:方式基本与OutputStream相同,只是字符流需要用到flush()强制写出缓冲区
  4. 字节流和字符流的区别
    • OutputStream没有使用close()方法,内容依然可以正常输出,Writer则不行(可以使用flush()强制刷新)
    • 字节流在处理的时候并不会使用到缓冲区,字符流会使用

基础概念

  1. 并发与并行
    • 并发:同一时间段内,交替执行,给人的感觉是在同一时间段内同时进行
    • 并行:同一时间点,同时执行,真正意义上的同时执行
  2. 线程与进程
    • 进程:一个内存中运行的应用程序,每个进程都有一个独立的内存空间,进程也是程序的一次执行过程,是系统运行程序的基本单位,进程之间共享数据不容易
    • 线程:线程是进程中的一个执行单元,一个进程中至少有一个线程,线程之间共享进程的数据
  3. 线程调度
    • 分时调度:所有线程轮流使用CPU,平均分配每个线程占用的时间
    • 抢占式调度:优先级高的优先使用CPU,如果都一样就随机(Java采用这种方式)
  4. 主线程:执行主方法的线程即main()方法

创建多线程的两种方式

  1. 继承Thread(java.lang.Thread)类 -> 重写run()方法 -> 调用start()方法启动线程
    • Thread中的方法
      1. 构造方法
        • public Thread() 分配一个新的线程对象
        • Public Thread(String name) 分配一个指定名字的新的线程对象
        • public Thread(Runnable target) 分配一个带有指定目标新的线程对象
        • public Thread(Runnable target, String name) 分配一个带有执行目标新的线程对象并指定名字
      2. 常用方法
        • public String getName() 获取线程名字
        • public void start() 启动执行线程,JVM调用线程的run()方法
        • public void run() 线程要执行的任务在此处定义
        • public static void sleep(long millis) 当前正在执行的线程暂停执行指定毫秒数
        • public static Thread currentThread() 返回当前正在执行的线程对象的引用
  2. 实现Runnable(jaba.lang.Runnable)接口 -> 重写run()方法 -> 创建Thread对象 -> 调用start()方法启动线程
  3. 两者区别
    • Runnable避免了但继承的局限性
    • Runnable增强了程序的扩展性,把设置线程任务和开启线程进行了分离
    • 线程池只能放实现Runnable或Callable类线程,不能直接放入继承Thread的类

同步技术,解决线程安全问题

  1. 线程安全问题:多个线程同时操作修改一份数据,出现非法数据的现象
  2. 同步代码块
    // 同步代码块中的锁对象(同步锁、对象监视器),可以是任意对象
    // 多个线程使用的锁对象必须是同一个
    // 锁对象可以保证只有一个线程在执行同步代码块的内容
    synchronized(同步锁) {可能会出现线程安全问题的代码块}
    // 线程执行到同步代码块部分,会检查同步锁是否被占有
    //   1. 如果被其他线程占有,则等待其他线程执行完毕释放锁,再占有锁,执行同步代码块
    //   2. 如果没有,则占有该同步锁,执行同步代码块
    // 程序频繁的判断锁、获取锁、释放锁,导致运行效率降低
    
  3. 同步方法
    public synchronized 返回值类型 方法名(参数...) {可能会出现线程安全问题的代码}
    
  4. 锁机制(Lock(java.util.concurrent.locks.Lock接口)锁,JDK1.5之后)
    • Lock 提供了比synchronized更广泛的锁定操作
    • 接口中的方法
      1. void lock() 获取锁
      2. void unlock() 释放锁
    • 使用步骤
      1. java.util.concurrent.locks.ReentrantLock 实现了 Lock 接口
      2. 在类的成员位置创建一个 ReentrantLock 对象
      3. 在可能出现线程安全问题的代码前调用Lock接口中的lock()方法获取锁
      4. 在可能出现线程安全问题的代码后调用Lock接口中的unlock()方法释放锁
    Lock.lock();
    可能会出现线程安全问题的代码
    // unlock写在finally最佳
    Lock.unlock();
    

线程状态

  1. 在Thread类中,有一个Thread.State内部类描述了线程的状态

    状态英文状态中文说明
    NEW新建创建线程对象,但一直没有调用启动的线程
    RUNNABLE运行正在JVM中执行的线程
    BLOCKED阻塞等待其他线程释放监视器锁的线程
    WAITING永久等待、无限等待调用Object.wait(),线程等待唤醒后才可以继续执行操作
    TIMED_WAITING计时等待、休眠、睡眠调用Object.wait(long time)、sleep(long time),线程在指定时间后自动唤醒
    TERMINATED死亡run()方法结束、调用stop()、执行出现异常的线程

线程通信,线程之间的等待和唤醒

  1. 几个方法
    • wait(long time) 在毫秒值后没有被唤醒,就会自动醒来,注意和sleep(long time)的区别,会释放锁
    • wait() 需要手动唤醒才可以醒来,会释放锁
    • notify() 唤醒等待的线程,如果有多个则随机唤醒一个,不会释放锁,会继续执行下去
    • notifyAll() 唤醒所有等待的线程,不会释放锁
  2. 生产者、消费者模型
    public static void main(String[] args) {
    
        // 生产者和消费者是单独的两个线程,一定要消费者先执行
        // 两个线程用一个同步锁进行通信,同一个同步锁控制两个线程的等待和唤醒
        Object obj = new Object();
        
        // 消费者线程
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    synchronized (obj) {
                        System.out.println("C:what kind of product i need");
                        try {
                            // 等待生产者生产
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("C:thanks it`s good");
                        System.out.println("-----------------------");
                        // 消费结束,唤醒生产者生产
                        obj.notify();
                    }
                }
            }
        }.start();
        
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    synchronized (obj) {
                        System.out.println("P:done");
                        // 生产结束,唤醒消费者消费
                        obj.notify();
                        try {
                            // 等待消费者消费
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }.start();
    }
    

线程池(JDK1.5后,内置了线程池)

  1. 容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,不需要反复创建线程而消耗过多的资源
  2. 线程池的使用
    • java.util.concurrent.Executors(类),用来生产线程池的工厂类
      1. public static ExecutorService newFixedhreadPool(int nThreads) 创建一个可重用固定线程数的线程池,参数nThread代表该线程池的最大线程数
    • java.util.concurrent.ExecutorService(接口),线程池接口
      1. public Future submit(Runnable task) 提交一个Runnable任务用于执行,获取一个线程并执行
      2. public void shutdown() 关闭/销毁线程池的方法,调用后程序也会停止
        ExecutorService threadpool = Executors.newFixedThreadPool(5);
        threadpool.submit(new Runnable() {
            @Override
            public void run() {
                // 即使没有死循环,程序也不会停止,因为线程池没有关闭
                System.out.println(Thread.currentThread().getName() + "is running");
            }
        });
        
  3. Java中线程池对象 java.util.concurrent.ThreadPoolExecutor
    • 构造方法参数
      1. 核心线程数量 不能小于0
      2. 最大线程数 不能小于等于0,最大数量>=核心线程数量
      3. 空闲线程最大存活时间 不能小于0
      4. 时间单位 时间单位TimeUnit类
      5. 任务队列 不能为null 任务在队列中等着,线程空闲了再取出执行
      6. 创建线程工厂 不能为null 创建线程的方式
      7. 任务的拒绝策略 不能为null 有四个值,当提交的任务 > 池子中最大线程数 + 队列容量时会触发任务的拒绝策略
        • AbortPolicy: 丢弃任务并抛出RejectedExcutionException异常(默认策略)
        • DiscardPolicy 丢弃任务,但是不抛出异常
        • DiscardOldestPolicy 抛弃队列中等待最久的任务,然后把当前任务加入到队列中
        • CallerRunsPolicy 调用任务的run()方法绕过线程池直接执行

volatile 强制线程在每次使用变量的时候,都去共享区域查看最新值

  1. 在Java中堆内存只有一块,而每一个线程都独有一块栈空间

原子性

  1. volatile只能保证每次在使用共享数据的时候时最新值
  2. 不能保证原子性

悲观锁和乐观锁

  1. 悲观锁,synchronized,总是从最坏的角度出发,认为每次获取数据的时候,别人都有可能修改,所以每次操作共享数据之前,都会上锁
  2. cas,原子类的操作方式。假设每次获取数据别人都不会修改,所以不会上锁。只不过在修改共享数据的时候,会检查一下,别人有没有修改过数据。
    • 如果别人修改过,那么再次获取最新的值
    • 如果没有被人修改,那么直接修改当前共享数据的值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值