第十八章【线程池、Lambda表达式】

一、等待唤醒机制

1、什么是等待唤醒机制

就是在一个线程进行了规定操作后,就调用**wait()进入等待状态, 等待其他线程执行完他们的指定代码过后,再用notify()**将其唤醒;在有多个线程进行等待时,如果需要,可以使用 notifyAll()来唤醒所有的等待线程

2、相关方法

public void wait(): 线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁,这时的线程状态即是 WAITING。它还要执行一个特别的动作,也即是“通知(notify)”在这个对象上等待的线程从wait set 中释放出来,重新进入到调度队列(ready queue)中
public void notify(): 选取所通知对象的 wait set 中的一个线程释放
public void notifyAll():释放所通知对象的 wait set 上的全部线程

3、注意事项

1、wait方法与notify方法必须要有同一个锁对象调用
2、wait方法与notify方法必须要在同步代码块或者是同步函数中使用
3、wait方法与notify方法是属于Object类的方法的

public static void main(String[] args) {
	Object lock = new Object();//同一个锁对象调用、属于Object类
	Runnable task = new Runnable() {
	@Override
	public void run() {
		String name = Thread.currentThread().getName();
		synchronized (lock) {	//同步代码块
			System.out.println(name + "获取了锁,即将释放锁并且进入等待状态");
			try {
				lock.wait();//在同步代码块或者是同步函数中使用
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(name + "醒来,并且获取了锁");}}};
    new Thread(task, "[A1]").start();
	new Thread(new Runnable() {	//匿名内部类
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock) {	//同步代码块
                    System.out.println(name + "获取了锁,即将通知所有人");
                    lock.notify();//在同步代码块或者是同步函数中使用
                    System.out.println(name + "即将在3秒之后释放锁");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(name + "释放锁");
                } }}, "[BBB]").start();}}

二、线程池

1、概念

线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源

三个好处:
1、降低资源消耗。
2、提高响应速度。
3、提高线程的可管理性。

2、方法

线程池工具类Executors中的方法:
public static ExecutorService newFixedThreadPool(int nThreads):返回线程池对象。(该方法创建线程池,且池中的线程个数可以指定最大数量)
public Future<?> submit(Runnable task):获取线程池中的某一个线程对象,并执行

使用步骤:
1、创建线程池对象。Executors.newFixedThreadPool(int nThread)
2、创建Runnable接口子类对象。(task)
3、提交Runnable接口子类对象。(take task)

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("我要一个教练");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("教练来了: " + Thread.currentThread().getName());
        System.out.println("教我游泳,教完后,教练回到了游泳池");}}
public class ThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(2);// 创建线程池对象,包含2个线程对象
        MyRunnable r = new MyRunnable();// 创建Runnable实例对象
        /* Thread t = new Thread(r);//自己创建线程对象的方式
        t.start(); //调用MyRunnable中的run()*/
        service.submit(r);// 从线程池中获取线程对象,然后调用MyRunnable中的run()
        service.submit(r);// 再获取个线程对象,调用MyRunnable中的run()
        service.submit(r);// 注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。
        // 将使用完的线程又归还到了线程池中
        service.shutdown();// 关闭线程池
    }}

三、Lambda表达式

1、格式

Lambda表达式的是匿名内部类的替代品,匿名内部类主要就是实现了接口的抽象方法,相对比下,匿名内部类格式鲜明同事可以轻松看懂,但语法复杂,Lambda的语法更简洁书写更方便,但可读性体验较差

如果使用Lambda表达式去实现一个接口的抽象方法,格式:

  1. 参数列表
  2. 箭头
  3. 方法体
格式:(参数列表)->{ 方法体 }
就是该抽象方法的具体实现,和匿名内部类中实现的方法是一回事

Lambda表示只适用于接口,而且这个接口必须只能有一个抽象方法。

2、省略规则

在Lambda标准格式的基础上,使用省略写法的规则为:
1、小括号内参数的类型可以省略;(如果要省略参数类型,所有的参数都应该省略类型)
2、如果小括号内有且仅有一个参,则小括号可以省略,类型也要省略;
3、如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号return关键字及语句分号(而且这三个元素,要同时的进行省略操作)。

3、练习:接口方法是无参无返回值

public interface Cook {
    void makeFood();}
public class Demo02Cook {
    public static void main(String[] args) {
        Cook c1 = new Cook() {	//创建了接口的对象(利用匿名内部类)
            @Override	//重写了接口的方法
            public void makeFood() {
                System.out.println("匿名内部:炖个汤");}};
        Cook c2 = () -> {	//利用Lambda简化匿名内部类,重写了接口的方法
            System.out.println("Lambda表达式:炒个菜");};
        cooking(c1);//输出结果:匿名内部:炖个汤
        cooking(c2);//输出结果:Lambda表达式:炒个菜
    }
    public static void cooking(Cook c) { //为了让在main方法中可以调用接口的方法
        c.makeFood();}}

4、练习:有参有返回值方法的使用

//练习:按照年龄升序将每个人排序并打印
public static void main(String[] args) {
        ArrayList<Person> list = new ArrayList<>();
        list.add(new Person("蔡徐坤", 18));
        list.add(new Person("张丹峰", 17));
        list.add(new Person("洪欣", 24));
        //3)进行按照年龄升序排序
        //方法一:匿名内部类是实现
        Comparator<Person> compartor = new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getAge() - o2.getAge();}};   
        //方法二:Lambda表达式
        Comparator<Person> compartor2 = (Person o1, Person o2) -> {
            return o1.getAge() - o2.getAge();};
		//方法三:使用Collections.sort(list,Comparator);
        Collections.sort(list, (Person o1, Person o2) -> {
            return o1.getAge() - o2.getAge();});
        for (Person p : list) {	//遍历打印
            System.out.println(p.getName() + "-" + p.getAge());}}
public class Person {
    private String name;
    private int age;
    快捷构造空参、满参、getter\setter
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值