等待和唤醒

线程等待和唤醒的方法

等待和唤醒,指的是两个线程或多个线程之间的相互等待或唤醒。
Java中提供了几个方法可以实现线程的等待和唤醒,这几个方法都来自Object类
image.png
Void Wait()
Void notify()
void notifyAll()

wait:线程等待

在一个同步代码块内,线程调用锁对象的 wait() 方法,让自己释放同步锁,并进入等待状态。只有其他线程调用了锁对象的 notify() 方法,等待的线程才可能解除等待,重新参与锁对象的竞争,线程如果再次得到锁,就可以从wait处继续向下运行。

notify:线程唤醒

在一个同步代码块内,线程调用锁对象的 notify() 方法,唤醒正在等待的另一个线程。(被唤醒的线程需要重新抢夺锁,成功之后可以从wait处继续往下执行。)如果有多个线程同时在等待,notify() 方法只会随机唤醒某个线程,如果想唤醒所有等待的线程,可以使用notifyAll() 方法。

注意:

等待和唤醒是多个线程之间的操作。
wait() ,notify(),notifyAll()方法 必须同步代码中使用锁对象调用。
notify()和notifyAll()方法并不释放锁,只是告诉在等待锁的线程可以去参与获得锁的竞争了,但被唤醒的线程不是马上得到锁,因为锁还在别人手里没释放。

生产者消费者

实际开发中,多个线程往往需要进行协作。最典型的场景就是生产者和消费者的模型:
假设有一个队列容器,生产者线程往队列加入数据,并通知(notify)消费者消费;在队列加满后,生产者线程需要进入等待(wait)。消费者线程往队列取出数据,并通知生产者生产;当队列为空时,消费者线程需要进入等待。

线程死锁

在多线程程序中,使用了多把锁,造成线程之间相互等待锁,程序无法向下执行。

容易产生死锁的条件:

l有多把锁
l有多个线程
l有同步代码块嵌套

注意:

开发多线程程序时,应该尽量避免三种条件同时出现在代码中,避免造成线程死锁。

线程互相等待对方释放锁,发生死锁,程序无法向下执行。

线程的状态

image.png
在Thread.State枚举类中,定义了线程的6种状态:
新建状态(NEW)
可运行状态(RUNNABLE)
终止状态(TERMINATED)
阻塞状态(BLOCKED)
无限等待状态(WAITING)
计时等待(TIMED_WAITING)

线程池

image.png

创建线程池

Executors类是线程池的工具类,通过Executors工具类可以创建线程池。
image.png

使用线程池

ExecutorService代表线程池,该类中提供submit方法用于处理提交的任务。
调用sumbit(任务)方法时,线程池会分配池中空闲的线程去执行对应的任务。
image.png

创建任务的两种方式:

实现Runnable接口,重写run方法。
实现Callable<返回类型>接口,重写call方法

线程池执行原理:
1.任务通过Submit方法提交给线程池。
2.线程池分配线程执行任务,执行结束后线程放回线程池,等待执行下次任务。
3.当线程池中没有空闲线程时,任务进入任务队列中等待,直到有空闲时间的线程去执行任务。

JDK1.8新特性

Lambda表达式

函数式编程思想概述

在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿数据做操作”面向对象思想强调“必须通过对象的形式来做事情”。
函数式思想则尽量忽略面向对象的复杂语法:“强调做什么,而不是以什么形式去做”。
而我们要学习的Lambda表达式就是函数式思想的体现

Lambda表达式的标准格式

组成Lambda表达式的三要素:形参列表,箭头,代码块。
image.png

Lambda表达式的省略格式

省略规则:
参数类型可以省略。
比如(Integer o1, Integer o2) 省略后 (o1, o2)
如果参数有且仅有一个,参数类型和小括号都可以省略。
比如(String s) 省略后 s
如果代码块的语句只有一条,可以省略大括号,分号和return。
image.png

Lambda表达式的前提

方法的参数是接口。
接口是只能有一个抽象方法。

说明:
有且只有一个抽象方法的接口,也叫做函数式接口。
可以在接口上加@Functionallnterface注解进行标记。
image.png

方法引用

方法引用概述

方法引用是java8的新特征之一,可以直接引用已有的Java类或对象的方法或构造器。方法引用与Lambda表达式结合使用,可以进一步简化代码。

方法引用格式

对象名:成员方法
类名:静态方法
类名:new

方法引用使用前提

1.Lambda表达式中仅仅调用一个方法。
2.调用的方法与要实现的抽象方法的参数和返回值一致时,可以使用方法引用代替。

Stream流

Stream流的三类方法

获取Stream流
创建一条流水线,并把数据放到流水线上准备操作。
中间方法
流水线上的操作,一次操作完毕之后,还可以继续进行其他操作。
终结方法
是流水线上的最后一个操作,一个Stream流只能有一次终结方法。
image.png

创建Stream流的方式

方式1:根据集合获取流
Collection根接口中提供了 stream( ) 方法可以获取流。
单列集合:直接调用stream()方法即可。
双列集合:先获取键和值的单列集合,再通过集合获取键和值各自的Stream流。
方式2:根据of方法获取流
Stream类提供了静态的 of( ) 方法,可以创建一个流对象。
Stream.of(T … values)

Stream流的常用方法

image.png

Stream流的使用注意

一个Stream流对象只能操作一次。
调用中间方法会返回断流,以便下次操作使用。
终结方法如果没有调用,中间方法也不会执行。

Stream流的收集

对Stream流操作完成之后,可以将流中的最终结果进行收集,存储到集合或数组中。
Stream流收集到数组

image.png

Stream流收集到集合

image.png