小新学Java13-【线程池、Lambda表达式】
一、等待唤醒机制
1.1线程间通信
概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。
1.2等待唤醒机制
什么是等待唤醒机制?
这是多个线程间的一种协作机制。谈到线程我们经常想到的是线程间的竞争( race),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制。更多时候你们更多是一起合作以完成某些任务。
就是在一个线程进行了规定操作后,就进入等待状态( wait()),等待其他线程执行完他们的指定代码过后再将其唤醒( notify()) ;
在有多个线程进行等待时,如果需要,可以使用notifyAll()来唤醒所有的等待线程。
wait/notify就是线程间的一种协作机制。
等待唤醒中的方法
等待唤醒机制就是用于解决线程间通信的问题的,使用到的3个方法的含义如下∶
1) wait :线程不再活动,不再参与调度,进入wait set中,因此不会浪费CPU资源,也不会去竞争锁了,这时的线程状态即是WAITING。它还要等着别的线程执行一个特别的动作,也即是"通知( notify )"在这个对象上等待的线程从wait set中释放出来,重新进入到调度队列( ready queue )中
2)notify :则选取所通知对象的wait set中的一个线程释放﹔例如,餐馆有空位置后,等候就餐最久的顾客最先入座。
3)notifyAll:则释放所通知对象的wait set上的全部线程。
调用wait和notify方法需要注意的细节
1)wait方法与notify方法必须要由同个锁对象调用。
因为∶对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。
2) wait方法与notify方法是属于Object类的方法的。
因为∶锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。
3)wait方法与notify方法必须要在同步代码块或者是同步函数中使用。
因为︰必须要通过锁对象调用这2个方法。
案例:
1.3生产者与消费者问题
二、线程池
2.1线程池思想概述
2.2线程池概念
线程池︰其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。
工作原理:
合理利用线程池能够带来三个好处︰
①降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
②提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
③提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
2.3线程池的使用
线程池:JDK1.5之后提供的
java.util.concurrent.Executors :线程池的工厂类,用来生成线程池
Executors类中的静态方法:
static ExecutorService newFixedThreadPool(int nThreads)创建一个可重用固定线程数的线程池
参数:
int nThreads:创建线程池中包含的线程数量
返回值:
ExecutorService接口,返回的是ExecutorService接口的实现类对象,我们可以使用ExecutorService接口接收(面向接口编程)
java.util.concurrent.ExecutorService :线程池接口
用来从线程池中获取线程,调用start方法,执行线程任务
submit( Runnable task)提交一个Runnable 任务用于执行
关闭/销毁线程池的方法
void shutdown ( )
线程池的使用步骤:
1.使用线程池的工厂类Executors里边提供的静态方法newFixedThreadPool生产一个指定线程数量的钱线程池
2.创建一个类,实现Runnable接口,重写run方法,设置线程任务
3.调用ExecutorService中的方法submit,传递线程任务(实现类),开启线程,执行run方法
4.调用ExecutorService中的方法shutdown销毁线程池(不建议执行)
三、Lambda表达式
3.1函数式编程思想概述
面向对象的思想:
做一件事情,找一个能解决这个事情的对象,调用对象的方法,完成事情。
函数式编程思想:
只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程。
3.2冗余的Runnable代码
传统写法
代码分析
3.3编程思想转换
做什么,而不是怎么做
我们真的希望创建一个匿名内部类对象吗?不。我们只是为了做这件事情而不得不创建一个对象。我们真正希望位的事情是∶将run方法体内的代码传递给Thread类知晓。
传递一段代码——这才是我们真正的目的。而创建对象只是受限于面向对象语法而不得不采取的一种手段方式。那,有没有更加简单的办法?如果我们将关注点从""怎么做"回归到"做什么"的本质上,就会发现只要能够更好地达到目的,过程与形式其实并不重要。
生活举例
3.4体验Lambda的更优写法
3.5回顾匿名内部类
使用实现类
使用匿名内部类
匿名内部类的好处与弊端
语义分析
3.6 Lambda标准格式
Lambda表达式的标准格式:
由三部分组成:
a.—些参数b.—个箭头
c.一段代码
格式:
(参数列表) -> {一些重写方法的代码};解释说明格式:
():接口中抽象方法的参数列表,没有参数,就空着;有参数就写出参数,多个参数使用逗号分隔->:传递的意思,把参数传递给方法体{ }
{ }:重写接口的抽象方法的方法体
3.7练习:使用Lambda标准格式
使用Lambda标准格式(无参无返回)
3.8 Lambda的参数和返回值
传统写法
代码分析
Lambda写法
3.9练习∶使用Lambda标准格式(有参有返回)
3.10 Lambda省略格式
可推导即可省略
省略规则
Lambda表达式:是可推导,可以省略
凡是根据上下文推导出来的内容,都可以省略书写可以省略的内容:
1)(参数列表):括号中参数列表的数据类型,可以省略不写
2)(参数列表):括号中的参数如果只有一个,那么类型和()都可以省略
3){一些代码}:如果{}中的代码只有一行,无论是否有返回值,都可以省略({}, return,分号)
注意:要省略, return,分号必须一起省略
3.11练习∶使用Lambda省略格式题目
3.12 Lambda的使用前提
Lambda的语法非常简洁,完全没有面向对象复杂的束缚。但是使用时有几个问题需要特别注意:
1.使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。
无论是JDK内置的 Runnable 、comparator接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。
2.使用Lambda必须具有上下文推断。
也就是方法的参数或局部变星类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。备注:有且仅有一个抽象方法的接口,称为“函数式接订"。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!