day18【线程池、Lambda表达式】

day18【线程池、Lambda表达式】

一. 等待唤醒机制

  • 目标
    • 让两条线程, 实现依次交替执行

1. 等待唤醒机制用到的两个方法

wait() : 让当前线程进入无限等待的状态
notify() : 随机唤醒一条等待的线程
notifyAll() : 唤醒所有等待的线程

wait()和notify()方法的特点:

  1. 两个方法必须在同步中.
  2. 两个方法必须使用锁对象来调用
  3. 两个方法是定义在Object类中

2. 生产者消费者

  • 生产者
package com.itheima._02waitnotify.demo02;

/**
 * 生产者线程
 */
public class Producer extends Thread {

    // 将BaoZi作为成员变量, 然后通过构造方法赋值
    private BaoZi baoZi;

    public Producer(BaoZi baoZi) {
        this.baoZi = baoZi;
    }

    @Override
    public void run() {
        // 无限循环
        while (true) {
            // 同步代码块
            synchronized (baoZi) {
                // 如果有包子
                if (baoZi.isHaveBaoZi) {
                    // 等待
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 代码执行到这里, 说明一定没有包子
                try {
                    System.out.println("【生产者】生产者正在生产包子... ... ");
                    Thread.sleep(1000);
                    System.out.println("【生产者】包子做好了, 消费者快来吃!");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                // 有包子了!!!
                baoZi.isHaveBaoZi = true;
                // 唤醒消费者来吃包子
                baoZi.notify();
            }
        }
    }
}

  • 消费者
package com.itheima._02waitnotify.demo02;

/**
 * 消费者线程
 */
public class Consumer extends Thread {

    private BaoZi baoZi;

    public Consumer(BaoZi baoZi) {
        this.baoZi = baoZi;
    }

    @Override
    public void run() {
        // 无限循环
        while (true) {
            // 同步代码块
            synchronized (baoZi) {
                // 如果没有包子
                if (!baoZi.isHaveBaoZi) {
                    // 等待
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                try {
                    // 代码执行到这里, 说明一定有包子
                    System.out.println("【消费者】消费者正在吃包子... ... ");
                    Thread.sleep(1000);
                    System.out.println("【消费者】包子吃完了, 生产者快来做!");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                // 包子没了
                baoZi.isHaveBaoZi = false;
                // 唤醒生产者来做包子
                baoZi.notify();
            }
        }
    }
}

  • 包子类
package com.itheima._02waitnotify.demo02;

/**
 * 这是一个包子类,
 *  类中有是否有包子的属性
 *
 *  这个类的对象会当做锁对象
 */
public class BaoZi {

    /**
     * 是否有包子
     * true: 有
     * false : 没有
     */
    boolean isHaveBaoZi = false;


}
  • 测试类
package com.itheima._02waitnotify.demo02;

public class Test {
    public static void main(String[] args) {
        BaoZi baoZi = new BaoZi();

        Producer p = new Producer(baoZi);

        Consumer c = new Consumer(baoZi);

        p.start();
        c.start();
    }
}

二. 线程池(了解)

三. Lambda表达式(重点)

1. 冗余的匿名内部类

new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("开启了一条新线程!~");
            }
        }).start(); // 参数中需要传入Runnable接口, 那么实际传入的应该是该接口的实现类对象
// 不得不创建一个类, 实现Runnable接口
// 为了不创建一个类, 所以使用匿名内部类
// 不得不重写run方法
// 不得不写出跟接口中的run方法, 方法名相同, 参数列表相同, 返回值类型也相同
// 最终我真正需要的代码其实就是方法体中的代码


new Thread(() -> System.out.println("开启了一条新线程!~")).start();

思想上的转变

  • 强调怎么做 >>> 强调做什么

2. Lambda表达式的格式解析

() : 一些参数
-> : 一个箭头
{} : 一段代码

() -> {} : 将小括号中的参数, 给大括号中的代码使用

如何将匿名内部类转换成Lambda表达式

  • Lambda中的小括号 : 匿名内部类中重写方法的参数列表
  • Lambda中的大括号 : 匿名内部类中重写方法的方法体

3. 无参无返回的lambda

  • 需求

    • 给定一个厨子Cook 接口,内含唯一的抽象方法makeFood ,且无参数、无返回值.
  • 接口

public interface Cook {
    void makeFood();
}
  • 测试类
package com.itheima._04lambda.demo02;

public class Demo02_无参无返回的lambda {
    public static void main(String[] args) {
        // 我们要做的是方法的调用!!!
        // 匿名内部类
        invokeCook(new Cook() {
            @Override
            public void makeFood() {
                System.out.println("吃饭啦!");
            }
        });

        // lambda的标准格式
        invokeCook(() -> {
            System.out.println("吃饭啦!");
        });

        // lambda的省略格式
        invokeCook(() -> System.out.println("吃饭啦!"));

    }

    // 如果方法的参数列表是接口, 那么实际传入的是它的实现类对象
    private static void invokeCook(Cook cook) {
        cook.makeFood();
    }

}

4. 无参有返回的lambda

  • 让接口中的抽象方法是无参有返回
  • 接口
public interface MyInter {
    String fun();
}
  • 测试类
package com.itheima._04lambda.demo03;

public class Demo03_无参有返回的lambda {
    public static void main(String[] args) {
        // 我们要做的, 方法的调用
        // 匿名内部类
        method(new MyInter() {
            @Override
            public String fun() {
                return "HelloLambda";
            }
        });

        // lambda的标准格式
        method(() -> {
            return "HelloLambda";
        });

        // lambda的省略格式
        method(() -> "HelloLambda");


    }

    // 模拟方法, 让接口作为方法的参数
    private static void method(MyInter mi) {
        System.out.println(mi.fun());
    }
}

5. 有参无返回的lambda

  • 接口
public interface Printable {
    void print(String s);
}
  • 测试类
package com.itheima._04lambda.demo04;

public class Demo04_有参无返回的lambda {
    public static void main(String[] args) {
        // 调用方法
        // 匿名内部类
        printString(new Printable() {
            @Override
            public void print(String s) {
                System.out.println(s);
            }
        });

        // lambda的标准格式
        printString((String s) -> {
            System.out.println(s);
        });

        // lambda的省略格式
        printString(s -> System.out.println(s));

    }

    // 模拟方法, 参数列表是接口
    private static void printString(Printable p) {
        p.print("HelloLambda");
    }
}

6. 有参有返回的lambda

  • 给定一个计算器Calculator 接口,内含抽象方法calc 可以将两个int数字相加得到和值
  • 接口
public interface Calculator {
    int calc(int a, int b);
}
  • 测试类
package com.itheima._04lambda.demo05;

public class Demo05_有参有返回的lambda {
    public static void main(String[] args) {
        // 匿名内部类
        invokeCalc(120, 130, new Calculator() {
            @Override
            public int calc(int a, int b) {
                return a + b;
            }
        });

        // lambda的标准格式
        invokeCalc(234, 432,(int a, int b) -> {
            return a + b;
        });

        // lambda的省略格式
        invokeCalc(234, 432, (a, b) -> a + b);
    }

    private static void invokeCalc(int a, int b, Calculator calculator) {
        int result = calculator.calc(a, b);
        System.out.println("结果是:" + result);
    }
}

Runnable

package com.itheima._04lambda.demo06;

public class Demo06_Runnable {
    public static void main(String[] args) {
        // 匿名内部类
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("新线程11");
            }
        }).start();

        // lambda的标准格式
        new Thread(() -> {
            System.out.println("新线程22");
        }).start();

        // lambda的省略格式
        new Thread(() -> System.out.println("新线程22")).start();
    }
}

Comparator

package com.itheima._04lambda.demo07;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Demo07_Comparator {
    public static void main(String[] args) {

        ArrayList<Integer> list = new ArrayList<>();

        // 添加元素
        Collections.addAll(list, 5, 2, 6, 3, 4, 8, 7, 9, 1);


        // 排序, 降序
        // 匿名内部类
        /*Collections.sort(list, new Comparator() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });*/

        // lambda的标准格式
        /*Collections.sort(list, (Integer o1, Integer o2) -> {
            return o2 - o1;
        });*/

        // lambda的省略格式
        Collections.sort(list, (o1, o2) -> o2 - o1);
        // Collections.sort(list, Comparator.reverseOrder());


        System.out.println(list);
    }
}

7. 省略格式

  • 遵循: 可推导可省略

省略规则

  1. 小括号中的数据类型可以省略
  2. 小括号中如果只有一个参数, 小括号可以省略
  3. 大括号中如果只有一条语句, 大括号和分号可以省略
  4. 大括号中如果只有一条语句, 还是一条返回语句, 大括号, 分号和return可以省略

8. lambda的前提条件

  • 存在一个接口, 接口中必须有且只有一个抽象方法
  • 让这个接口作为方法的参数

你可能感兴趣的:(Java基础笔记)