| 
 
| day07 线程间通信 线程池 Lambda表达式线程间通信:多个线程在处理统一资源,但是多个线程的处理动作却不相同(线程的任务不同,需要协调合作) [size=18.6667px]等待唤醒机制:
 调用 wait() 和 notify() 需要注意的细节:
 1. wait() 与 notify() 必须要由"同一个锁对象"调用
 因为对应的锁对象可以通过 notify() 唤醒使用同一个锁对象调用的 wait() 后的线程
 2. wait() 与 notify() 是属于Object类的方法
 因为锁对象可以是任意对象, 而任意对象的所属类都是继承了Object类的
 3. wait() 与 notify() 必须要在"同步代码块"或者是"同步方法"中使用
 因为必须要通过锁对象调用这2个方法
 吃包子代码实现:
 1:定义一个包子类:
 public class Baozi {
 
 String pi;
 String xian;
 boolean you = false;  // 一开始没有包子
 }
 2:定义一个包子铺:
 public class BaoziPu extends Thread {
 
 // 定义包子成员变量, 作为共享的数据
 Baozi baozi;
 
 // 定义有参构造方法, 便于将共享的同一个包子对象传入
 public BaoziPu(Baozi baozi) {
 this.baozi = baozi;
 }
 
 // 定义包子铺的任务
 
 @Override
 public void run() {
 // 定义一个计数器变量, 用于判断生产什么包子
 int count = 0;
 // 循环生产包子
 while (true) {
 // 使用同步代码块
 synchronized (baozi) {
 // 先判断是不是有包子, 有包子则先等待
 if (baozi.you) {
 try {
 baozi.wait();
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 // 如果能执行到这里, 说明被吃货唤醒了, 要开始做包子. 先判断做什么馅
 if (count % 2 == 0) {
 // 做薄皮三鲜
 baozi.pi = "薄皮";
 baozi.xian = "三鲜馅";
 } else {
 // 做冰皮牛肉
 baozi.pi = "冰皮";
 baozi.xian = "牛肉馅";
 }
 // 将计数器增加
 count++;
 // 打印一句话模拟包子制作过程
 System.out.println("[包子铺] 正在生产" + baozi.pi + baozi.xian + "的包子");
 try {
 Thread.sleep(2000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 // 包子做好了, 要修改包子的状态
 baozi.you = true;
 // 通知吃货来吃
 System.out.println("[包子铺] 做好了" + baozi.pi + baozi.xian + "的包子, 快来取餐!");
 baozi.notify();
 }
 }
 }
 }
 3:定义吃货类:
 public class ChiHuo extends Thread {
 
 Baozi baozi;
 
 public ChiHuo(Baozi baozi) {
 this.baozi = baozi;
 }
 
 @Override
 public void run() {
 // 循环吃包子
 while (true) {
 // 使用同步代码块
 synchronized (baozi) {
 // 先判断是不是没有包子, 没有包子则等待
 if (!baozi.you) {
 try {
 baozi.wait();
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 
 // 如果代码能执行到这里 说明被包子铺唤醒了, 则有包子了, 开始吃包子
 System.out.println("[吃货] 我正在吃" + baozi.pi + baozi.xian + "的包子, 真香!");
 // 吃完了修改状态
 baozi.you = false;
 // 通知包子铺再去生产包子
 System.out.println("[吃货] 吃完了, 老板再来一锅!");
 baozi.notify();
 System.out.println("---------------------------");
 }
 }
 }
 }
 4测试类
 public class Test {
 public static void main(String[] args) {
 // 创建一个包子对象, 同时传入包子铺和吃货, 作为共享的锁对象
 Baozi baozi = new Baozi();
 
 // 创建包子铺, 并开始
 new BaoziPu(baozi).start();
 // 创建吃货, 并开始
 new ChiHuo(baozi).start();
 }
 }
 
 线程池:容纳多个线程的容器,线程可以反复使用,省去了频繁创建线程对象的操作.
 好处:1.降低资源消耗   2.提高响应速度  3.提高线程的可管理性
 ExecutorService es = Executors.newFixedThreadPool(线程数量);
 [size=18.6667px]es.submit:提交一个Runnable任务
 Lambda表达式:
 Lambda表达式的3个部分:
 1. 一些参数 ()
 接口中抽象方法的参数列表. 没参数就空着; 有参数就写, 多个参数用逗号分隔
 2. 一个箭头 ->
 将参数传递给方法体
 3. 一段代码 {}
 重写接口抽象方法的方法体
 使用前提:      1. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。无论是JDK内置的 Runnable 、 Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。  2. 使用Lambda必须具有上下文推断。也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。
 可以省略的部分:
 1. (参数列表): 参数"类型"可以省略 (a, b) -> {}
 2. (参数列表): 如果参数只有1个, 则"类型"和"小括号"都可以省略  a -> sout(a)
 3. {一些代码}: 如果只有一条代码, 则"大括号", "return", "分号"都可以"一起省略"
 
 
 day08 File类 递归笔记
 File类:   file:文件   directory:目录   path:路径
 测试File类的获取方法:
 String getAbsolutePath(): 返回此File的绝对路径名字符串
 String getPath(): 获取File对象的封装路径 (创建对象时传入的路径)
 String getName(): 获取File对象的文件名或目录名
 long length(): 获取File表示的文件大小的字节数 (不能获取目录的大小)
 
 File f1 = new File("d:\\a.txt");  // 测试使用绝对路径
 String f1AbsolutePath = f1.getAbsolutePath();
 System.out.println(f1AbsolutePath);  // d:\a.txt
 
 
 测试File类的判断方法
 boolean exists(): 判断File对象代表的文件或目录是否实际存在
 boolean isDirectory(): 判断File表示的是否为目录
 boolean isFile(): 判断File表示的是否为文件
 
 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)
 
 
 File类的获取目录中内容的方法
 String[] list(): 获取当前File目录下的所有子文件或目录的名字数组
 File[] listFiles(): 获取当前File目录中的所有子文件或目录的File对象数组
 
 递归:
 递归思想:
 遇到一个问题时, 将该问题拆解成可以解决的小问题, 如果解决不了, 继续拆解为更小的问题. 如果小问题解决了, 大问题也就能够解决
 Java中实现递归的方式:
 方法内部调用方法自己 (所以必须定义方法)
 递归的分类:
 直接递归: 方法自己调用方法
 间接递归: A方法调用B方法, B方法调用C方法, C方法调用A方法
 递归时的注意事项:
 1. 递归要有限定条件(出口), 保证递归能够停止(就是在某种情况下方法不再调用自己), 否则会栈内存溢出
 2. 递归次数不能太多, 否则会栈内存溢出
 3. 构造方法不能递归
 递归的使用前提:
 调用方法时, 方法的主体不变, 但每次传递的参数值不同, 可以使用递归
 需求:求1~n的和
 分析:
 求1~5的和: 5+4+3+2+1
 5~1的和 = 5 + ((5-1)~1的和)
 4~1的和 = 4 + ((4-1)~1的和)
 3~1的和 = 3 + (2~1的和)
 2~1的和 = 2 + (1~1的和)
 1~1的和 = 1;
 
 public class Test {
 public static void main(String[] args) {
 int sum = sum(5);
 System.out.println(sum);  // 15
 }
 
 // 定义方法: 求1~n的和
 public static int sum(int n) {
 // 递归的结束出口
 if (n == 1) {  // 如果问题能解决, 直接返回结果
 return 1;
 }
 // 如果能执行到这里, 说明问题没有解决, 要递归解决
 return n + sum(n-1);
 }
 }
 
 递归打印多级目录
 public class Test {
 
 public static void main(String[] args) {
 File dir = new File("day08");
 printAllFile(dir);
 }
 
 // 将每次不能解决的问题, 定义成方法: 打印某个目录中的所有文件和目录路径
 public static void printAllFile(File dir) {  // 参数是目录的File对象
 // 为了打印所有目录的路径, 在这里统一打印目录
 System.out.println(dir);
 
 // 先获取传入的目录中的所有子文件和子目录
 File[] childFiles = dir.listFiles();  // childFiles是一个变量名, 表示所有 子File对象
 for (File childFile : childFiles) {
 // 判断每个 子File对象 是文件还是目录
 if (childFile.isFile()) {
 // 是文件, 则打印路径
 System.out.println(childFile);
 } else if (childFile.isDirectory()) {
 // 是目录, 则递归调用方法
 printAllFile(childFile);  // 注意!! 参数要传递 子目录对象!!!
 }
 }
 }
 }
 
 boolean endsWith(String suffix): 判断字符串是否以指定的字符串结尾
 判断文件后缀: boolean b = "aaa.JAVA".endsWith(".java");
 String toLowerCase(): 将字符串转为小写字母
 String s = "aaa.JAVA".toLowerCase();
 s: "aaa.java"
 
 
 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: 文件的名称          (子路径)
 
 
 
 
 | 
 |