A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 养只猫叫冰棍儿 初级黑马   /  2018-11-26 10:51  /  700 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 养只猫叫冰棍儿 于 2018-11-26 11:18 编辑

Day07
线程间通信:
        多个线程在处理同一个资源, 但是多个线程的处理动作却不相同(线程的任务不同, 需要协调合作)
为什么要进行线程间通信:
        通常是竞争关系: 多个线程并发执行时, 在默认情况下CPU是随机切换线程的.
        有时也"需要合作": 当我们需要多个线程来共同完成一件任务, 并且我们希望他们有规律的执行, 那么多线程之间需要一些协调通信, 以此来帮我们达到多线程共同操作一份数据
如何实现线程间通信:
        "等待唤醒机制"
等待唤醒机制:
        wait/notify, 就是"线程间的一种协作机制", 用于实现线程间通信
等待唤醒中的方法
java.lang.Object类:
        // 成员方法 (只能通过"锁对象"调用)
        void notify(): 随机唤醒在同一个锁对象上的某一个处于等待状态的线程
        void notifyAll(): 唤醒所有在同一个锁对象上处于等待状态的线程
        void wait(): 让当前线程处于无限等待状态, 同时释放锁
wait和notify/notifyAll的执行原理:
        wait:
                线程不再活动, 不再参与调度, 进入 wait set 中, 因此不会浪费 CPU 资源, 也不会去竞争锁, 这时的线程状态即是"WAITING". 它还要等着别的线程执行"通知(notify)", 让在锁对象上等待的线程从 wait set 中释放出来, 重新进入到调度队列(ready queue)中
        notify/notifyAll:
                哪怕只通知了一个等待的线程, 被通知线程也不能立即恢复执行, 因为它当初中断的地方是在同步块内, 而
此刻它已经不持有锁, 所以它需要"再次尝试去获取锁"(很可能面临其它线程的竞争), 成功后才能在当初调用 wait() 之后的地方恢复执行
                总结如下:
如果能获取锁, 线程就从"WAITING"状态变成"RUNNABLE"状态
否则, 从 wait set 出来, 又进入entry set, 线程就从"WAITING"状态又变成"BLOCKED"状态
调用 wait() 和 notify() 需要注意的细节:
        1. wait() 与 notify() 必须要由"同一个锁对象"调用
                因为对应的锁对象可以通过 notify() 唤醒使用同一个锁对象调用的 wait() 后的线程
        2. wait() 与 notify() 是属于Object类的方法
                因为锁对象可以是任意对象, 而任意对象的所属类都是继承了Object类的
        3. wait() 与 notify() 必须要在"同步代码块"或者是"同步方法"中使用
                因为必须要通过锁对象调用这2个方法
普通创建线程方式的缺点:
        "创建"线程和"销毁"线程都是比较占用内存和CPU的操作.
        对于一些数量多, 执行时间短的任务, 频繁的创建和销毁线程来执行, 会降低程序运行效率.

线程池:
        一个容纳多个线程的容器(集合)

线程池可以解决的问题:
        其中的线程可以反复使用, 省去了频繁创建线程对象的操作, 无需反复创建线程而消耗过多资源

线程池的工作原理:
        提前创建好多个线程对象, 放在集合中. 多个任务来了反复使用这些线程对象来执行
java.util.concurrent.Executors类: 线程池工厂类, 用于创建和管理线程池
        // 静态方法:
        static ExecutorService newFixedThreadPool(int nThreads): 创建固定数量线程的线程池(常用)

java.util.concurrent.ExecutorService接口: 真正执行任务的线程池服务
        // 成员方法:
        Future submit(Runnable task): 提交一个Runnable任务
        void shutdown(): 通知线程执行完任务后关闭. 如不调此方法, 则线程执行完任务后仍在运行以便重复使用
        
线程池的创建和使用步骤:
        1. 使用Executors的静态方法 newFixedThreadPool(int nThreads) 创建线程池ExecutorService
        2. 创建一个任务类, 实现Runnable接口, 重写run()方法
        3. 调用ExecutorService对象的 submit(Runnable task) 方法, 传递任务给线程池, 执行任务
        4. 调用ExecutorService对象的 shutdown() 方法, 销毁线程池 (不建议执行)
函数式:
        在数学中, 函数就是有输入量, 输出量的一套计算方案, 也就是"传入什么东西, 得到什么结果"
    y = f(x)
面向对象: 强调"用哪个对象的哪个方法"来做事 (注重语法形式: 继承 方法重写)
函数式: 强调"传入的参数 和 要执行的代码"
函数式编程的好处:
        简化代码编写 (使用 λ Lambda表达式, 简化匿名内部类的代码)
Lambda表达式的3个部分:
    1. 一些参数 ()
                接口中抽象方法的参数列表. 没参数就空着; 有参数就写, 多个参数用逗号分隔
    2. 一个箭头 ->
                将参数传递给方法体
    3. 一段代码 {}
                重写接口抽象方法的方法体
格式:
// 写成多行
(数据类型 变量名, 数据类型 变量名) -> {
        一些重写方法的代码
        一些重写方法的代码
        ...
    }
// 如果代码只有一行, 也可以合并写成一行
(参数列表) -> {一些重写方法的代码}
函数式接口:
        函数式接口: "有且仅有一个抽象方法的接口"
        但函数式接口对于 哪些方法算作抽象方法 有特殊规定:
                1. 有方法体的方法"不算作"抽象方法, 如默认方法, 静态方法, 私有方法
                2. 如果一个抽象方法 与 java.lang.Object类中的方法 定义相同的, 也"不算作"抽象方法
                        因为任何实现本接口的实现类, 都会直接或间接继承java.lang.Object类的public的方法, 所以在创建实现类时其实不用重写该抽象方法, 也就不算作抽象方法
Lambda表达式的省略原则:
"可推导的都可省略" (凡是能根据前后代码能猜测出来的代码, 都可以省略不写)
    可以省略的部分:
        1. (参数列表): 参数"类型"可以省略 (a, b) -> {}
        2. (参数列表): 如果参数只有1个, 则"类型"和"小括号"都可以省略  a -> sout(a)
        3. {一些代码}: 如果只有一条代码, 则"大括号", "return", "分号"都可以"一起省略"
*函数式接口:
        函数式接口: "有且仅有一个抽象方法的接口"
        但函数式接口对于 哪些方法算作抽象方法 有特殊规定:
                1. 有方法体的方法"不算作"抽象方法, 如默认方法, 静态方法, 私有方法
                2. 如果一个抽象方法 与 java.lang.Object类中的方法 定义相同的, 也"不算作"抽象方法
                        因为任何实现本接口的实现类, 都会直接或间接继承java.lang.Object类的public的方法, 所以在创建实现类时其实不用重写该抽象方法, 也就不算作抽象方法
Lambda表达式的使用前提:
    1. Lambda只能用于接口, 且"接口中有且仅有一个抽象方法"(也称为"函数式接口") 普通类, 抽象类不能用
    2. 使用Lambda必须具有上下文推断
        接口中只能有一个抽象方法, 才能推断出来重写的是这个抽象方法
简而言之: 参数类型必须是函数式接口
比如以下构造方法
        Thread(Runnable r): 该构造方法的参数类型是Runnable

        // Runnable接口中, 有且仅有一个抽象方法, 该接口就是一个函数式接口, 可以使用Lambda表达式
        public interface Runnable {
            public abstract void run();
        }
        
                // Comparator接口中, 有且仅有一个抽象方法
        public interface Comparator<T> {
            // 这是该接口中有且仅有的一个抽象方法
            int compare(T o1, T o2);
            // 该方法与Object类中equals定义相同, 所以不算抽象方法
            boolean equals(Object obj);
            // 一些default方法, 有方法体, 不算抽象方法
            // 一些静态方法, 有方法体, 不算抽象方法
        }
                // 我们今天自己定义的接口, 也满足函数式接口的要求
                public interface Cook {
                        void makeFood();
                }
// Lambda省略格式
new Thread(() -> System.out.println(Thread.currentThread().getName() + "新线程创建了")).start();
// Lambda省略格式
invokeCook(()-> System.out.println("Lambda标准格式: 吃饭啦"));

// Lambda省略格式
Arrays.sort(arr, (o1, o2) -> o1.getAge() - o2.getAge());

// Lambda省略格式
invokeCalc(120, 130, (a, b)->a + b);

Day08
File类:
        IO流, 操作磁盘上的文件(文件夹/目录)
递归:
        方法自己调用自己
        思想: 大问题解决不了 = 可以解决的一个小问题 + 无法解决的另一个小问题
                        无法解决的另一个小问题 = 可以解决的一个小问题 + 无法解决的另一个小问题
                                ...
                                        无法解决的另一个小问题 -> 可以解决的小问题
java.io.File类: "文件"和"目录"的路径名的抽象表现形式, 主要用于文件和目录的创建, 查找和删除等操作
        private String path;
"D:\itheima-teach\sjz-javaee-10\s2-进阶\08\avi\02_File类的概述.avi"
"D:\itheima-teach\sjz-javaee-10\s2-进阶\"
String -> File
Input输入 Output输出
我们可以对File进行的操作:
        创建文件/目录
        删除文件/目录
        获取文件/目录
        判断文件/目录是否存在
        对目录进行遍历
        获取文件的大小
        
重要英文单词的含义: (起变量名时会用到)
        file: 文件
        directory: 目录
        path: 路径
java.io.File类: 文件和目录的路径名的抽象表现形式, 主要用于文件和目录的创建, 查找和删除等操作
        // 静态成员变量
    static String pathSeparator: 路径分隔符的字符串形式
    static char pathSeparatorChar: 路径分隔符的char形式
            Windows系统是 分号;  
        Linux系统是 冒号:
    static String separator: 文件名称分隔符的字符串形式
    static char separatorChar: 文件名称分隔符的char形式
            Window系统是 反斜杠\
        Linux系统是 正斜杠/
绝对路径:
以盘符开始的路径
        如: "D:\\a\\hi.txt"
相对路径:
不以盘符开始的简化路径. IDEA项目, 相对于项目的根目录
        如: "a\\1.mp3", "123.txt"
        "d:\\t"
        
注意事项:
        1. 路径不区分大小写 (在Windows系统中不区分大小写, Linux, Mac区分)
        2. 路径一般写成字符串, 而字符串中一个\是转义, 所以要写两个\\
java.io.File类: 文件和目录的路径名的抽象表现形式, 主要用于文件和目录的创建, 查找和删除等操作
        // 构造方法(创建了File对象, 并将其指向该路径. 不会真正在磁盘上创建这个文件)
        new File("D:\\a\\hi.txt")
    "D:\\a\\b\\c\\hi.txt"
    "D:\\a\\"  "b\\c\\hi.txt"
        File File(String pathname): 根据 路径字符串 封装一个File对象
        File File(String parent, String child): 根据 父路径字符串 和 子路径字符串 封装File对象
        File File(File parent, String child): 根据 父路径的File对象 和 子路径 封装File对象

java.io.File类
    // 常用获取方法
    String getAbsolutePath(): 返回此File的绝对路径名字符串
    String getPath(): 获取File对象的封装路径 (创建对象时传入的路径)
    String getName(): 获取File对象的文件名或目录名  d:\a\b\c\aaa.txt
long length(): 获取File表示的"文件"大小的字节byte数 (不能获取目录的大小)
java.io.File类
    // 常用判断方法
        boolean exists(): 判断File对象代表的文件或目录是否实际存在
        boolean isDirectory(): 判断File表示的是否为目录
        boolean isFile(): 判断File表示的是否为文件
java.io.File类
    // 常用创建删除方法
        boolean createNewFile(): 当文件不存在时, 创建一个新的空文件
                false: 路径已经存在(无论文件还是目录)   
        抛IO异常: 写的路径不符合逻辑 (Y:\\a.txt\dsfsd)
        boolean delete(): 删除由此File表示的文件或目录.
        删除目录时: 必须是空目录
        boolean mkdir(): 创建File表示的目录  "d:\\a\\b\\c\\我的目录"
                false: 1. 路径已经存在(无论文件还是目录)   2. 写的路径不符合逻辑 (Y:\\a.txt\dsfsd)
        boolean mkdirs(): 创建File表示的多级目录   "d:\\a\\b\\c\\我的目录"
                false: 1. 路径已经存在(无论文件还是目录)   2. 写的路径不符合逻辑 (Y:\\a.txt\ds)
java.io.File类
    // 常用获取目录中内容的方法
        String[] list(): 获取当前File目录下的所有子文件或目录的名字数组
        File[] listFiles(): 获取当前File目录中的所有子文件或目录的File对象数组

注意:
只能用表示目录的File对象调用
       用文件的File对象, 或者路径不存在, 调用会报错

递归思想:
        遇到一个问题时, 将该问题拆解成可以解决的小问题, 如果解决不了, 继续拆解为更小的问题. 如果小问题解决了, 大问题也就能够解决
Java中实现递归的方式:
        方法内部调用方法自己 (所以必须定义方法)
递归的分类:
        直接递归: 方法自己调用方法
        间接递归: A方法调用B方法, B方法调用C方法, C方法调用A方法
        
递归时的注意事项:
    1. 递归要有限定条件(出口), 保证递归能够停止(就是在某种情况下方法不再调用自己), 否则会栈内存溢出
    2. 递归次数不能太多, 否则会栈内存溢出
    3. 构造方法不能递归
递归的使用前提:
        调用方法时, 方法的主体不变, 但每次传递的参数值不同, 可以使用递归
java.io.File类:  Filter过滤器
        File[] listFiles(FileFilter filter): 返回文件过滤器过滤后的File对象数组
        File[] listFiles(FilenameFilter filter): 返回文件过滤器过滤后的File对象数组
java.io.FileFilter接口: 用于File对象的过滤器
        boolean accept(File pathName): true则会将参数的File对象加入返回的File[], false则不加入
java.io.FilenameFilter接口: 将File对象拆分为父路径和子路径来判断的过滤器
        boolean accept(File dir, String name): true则会将参数的File对象加入返回的File[], false则不加入
                dir: 被找到的文件所在的目录 (父路径)
                name: 文件的名称          (子路径)


0 个回复

您需要登录后才可以回帖 登录 | 加入黑马