等待和唤醒
线程等待和唤醒的方法
等待和唤醒,指的是两个线程或多个线程之间的相互等待或唤醒。
Java中提供了几个方法可以实现线程的等待和唤醒,这几个方法都来自Object类
Void Wait()
Void notify()
void notifyAll()
wait:线程等待
在一个同步代码块内,线程调用锁对象的 wait() 方法,让自己释放同步锁,并进入等待状态。只有其他线程调用了锁对象的 notify() 方法,等待的线程才可能解除等待,重新参与锁对象的竞争,线程如果再次得到锁,就可以从wait处继续向下运行。
notify:线程唤醒
在一个同步代码块内,线程调用锁对象的 notify() 方法,唤醒正在等待的另一个线程。(被唤醒的线程需要重新抢夺锁,成功之后可以从wait处继续往下执行。)如果有多个线程同时在等待,notify() 方法只会随机唤醒某个线程,如果想唤醒所有等待的线程,可以使用notifyAll() 方法。
注意:
等待和唤醒是多个线程之间的操作。
wait() ,notify(),notifyAll()方法 必须同步代码中使用锁对象调用。
notify()和notifyAll()方法并不释放锁,只是告诉在等待锁的线程可以去参与获得锁的竞争了,但被唤醒的线程不是马上得到锁,因为锁还在别人手里没释放。
生产者消费者
实际开发中,多个线程往往需要进行协作。最典型的场景就是生产者和消费者的模型:
假设有一个队列容器,生产者线程往队列加入数据,并通知(notify)消费者消费;在队列加满后,生产者线程需要进入等待(wait)。消费者线程往队列取出数据,并通知生产者生产;当队列为空时,消费者线程需要进入等待。
线程死锁
在多线程程序中,使用了多把锁,造成线程之间相互等待锁,程序无法向下执行。
容易产生死锁的条件:
注意:
开发多线程程序时,应该尽量避免三种条件同时出现在代码中,避免造成线程死锁。
线程互相等待对方释放锁,发生死锁,程序无法向下执行。
线程的状态
在Thread.State枚举类中,定义了线程的6种状态:
新建状态(NEW)
可运行状态(RUNNABLE)
终止状态(TERMINATED)
阻塞状态(BLOCKED)
无限等待状态(WAITING)
计时等待(TIMED_WAITING)
线程池
创建线程池
Executors类是线程池的工具类,通过Executors工具类可以创建线程池。
使用线程池
ExecutorService代表线程池,该类中提供submit方法用于处理提交的任务。
调用sumbit(任务)方法时,线程池会分配池中空闲的线程去执行对应的任务。
创建任务的两种方式:
实现Runnable接口,重写run方法。
实现Callable<返回类型>接口,重写call方法
线程池执行原理:
1.任务通过Submit方法提交给线程池。
2.线程池分配线程执行任务,执行结束后线程放回线程池,等待执行下次任务。
3.当线程池中没有空闲线程时,任务进入任务队列中等待,直到有空闲时间的线程去执行任务。
JDK1.8新特性
Lambda表达式
函数式编程思想概述
在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿数据做操作”面向对象思想强调“必须通过对象的形式来做事情”。
函数式思想则尽量忽略面向对象的复杂语法:“强调做什么,而不是以什么形式去做”。
而我们要学习的Lambda表达式就是函数式思想的体现
Lambda表达式的标准格式
Lambda表达式的省略格式
省略规则:
参数类型可以省略。
比如(Integer o1, Integer o2) 省略后 (o1, o2)
如果参数有且仅有一个,参数类型和小括号都可以省略。
比如(String s) 省略后 s
如果代码块的语句只有一条,可以省略大括号,分号和return。
Lambda表达式的前提
方法的参数是接口。
接口是只能有一个抽象方法。
说明:
有且只有一个抽象方法的接口,也叫做函数式接口。
可以在接口上加@Functionallnterface注解进行标记。
方法引用
方法引用概述
方法引用是java8的新特征之一,可以直接引用已有的Java类或对象的方法或构造器。方法引用与Lambda表达式结合使用,可以进一步简化代码。
方法引用格式
方法引用使用前提
1.Lambda表达式中仅仅调用一个方法。
2.调用的方法与要实现的抽象方法的参数和返回值一致时,可以使用方法引用代替。
Stream流
Stream流的三类方法
获取Stream流
创建一条流水线,并把数据放到流水线上准备操作。
中间方法
流水线上的操作,一次操作完毕之后,还可以继续进行其他操作。
终结方法
是流水线上的最后一个操作,一个Stream流只能有一次终结方法。
创建Stream流的方式
方式1:根据集合获取流
Collection根接口中提供了 stream( ) 方法可以获取流。
单列集合:直接调用stream()方法即可。
双列集合:先获取键和值的单列集合,再通过集合获取键和值各自的Stream流。
方式2:根据of方法获取流
Stream类提供了静态的 of( ) 方法,可以创建一个流对象。
Stream.of(T … values)
Stream流的常用方法
Stream流的使用注意
一个Stream流对象只能操作一次。
调用中间方法会返回断流,以便下次操作使用。
终结方法如果没有调用,中间方法也不会执行。
Stream流的收集
对Stream流操作完成之后,可以将流中的最终结果进行收集,存储到集合或数组中。
Stream流收集到数组