线程状态
- 线程从创建到销毁的过程称为线程的生命周期,在线程的生命周期内一共有六种状态
线程状态 | 导致状态发生条件 |
---|---|
NEW(新建) | 线程刚被创建,但是并未启动。还没调用start方法。MyThread t = new MyThread()只有线程对象,没有线程特征 创建线程对象时 |
Blocked(锁阻塞) | 当线程试图获取锁对象,而该锁对象被其他的线程持有,则该线程进入锁阻塞状态;当该线程获取到锁对象时,该线程将变成可运行状态 等待锁对象时 |
Waiting(无限等待) | 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒 调用wait()方法时 |
Timed Waiting(计时等待) | 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait 调用sleep()方法时 |
Teminated(被终止) | 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡 run方法执行结束时 |
等待唤醒机制_
- 使用等待和唤醒实现多条线程之间有规律的执行
实现等待唤醒机制:
使用锁对象调用wait()方法进入无限等待
使用锁对象调用notify()方法唤醒线程
调用wait(),notify()方法的锁对象要一致
示例:
// 计时等待
public class Text {
public static void main(String[] args)throws Exception {
for (int i = 0; i < 10; i++) {
System.out.println("每打印一次,暂停3秒");
// 暂停3秒
Thread.sleep(3000);
}
}
}
// 无限等待
public class Text {
// 锁对象
public static Object obj = new Object();
public static void main(String[] args)throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("准备进入无限等待...");
try {
obj.wait();// 进入无限等待中
} catch (InterruptedException e) {
e.printStackTrace();
}
// 等待被其他线程唤醒
}
}
}).start();
}
}
用等待唤醒机制让两个线程交替执行
// 锁对象
public static Object obj = new Object();
// 全局开关
public static boolean flag = false;
public static void main(String[] args) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synchronized (obj) {
if (flag == false)
try {
obj.wait();// 进入无限等待中
} catch (InterruptedException e) {
e.printStackTrace();
}
if (flag == true) {
System.out.println(Thread.currentThread().getName() + "打印的值为" + i);
// 唤醒其他线程
obj.notify();
// 改变开关
flag = false;
}
}
}
}
}, "线程1:").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synchronized (obj) {
if (flag == true)
try {
obj.wait();// 进入无限等待中
} catch (InterruptedException e) {
e.printStackTrace();
}
if (flag == false) {
System.out.println(Thread.currentThread().getName() + "打印的值为" + i);
// 唤醒其他线程
obj.notify();
// 改变开关
flag = true;
}
}
}
}
}, "线程2:").start();
}
}
- 等待唤醒机制程序的执行流程
- 不管是否使用等待唤醒机制,线程的调度都是抢占式
- 线程进入无限等待,线程就会释放锁cpu,也不会再去争夺
- 唤醒其他线程,当前唤醒线程是不会释放锁cpu的
- 无限等待线程被唤醒,拿到锁对象后,会从进入无限等待的位置继续往下执行
Lambda表达式
-
标准格式
-(参数类型 参数名,参数类型 参数名,...)->{ 代码块 }
-
格式说明
- 小括号中的参数类型,参数个数,参数顺序要和函数式接口中抽象方法的形参列表一致
- -> 固定格式,表示指向
- 大括号中的内容其实就是之前重写接口中抽象方法的方法体 -
Lambda的使用前提条件
- 接口中只有一个抽象方法的接口,才可以使用Lambda表达式
- 只有一个抽象方法的接口叫做函数式接口,函数式接口可以使用@FunctionalInterface注解标识 -
通过Lambda表达式实现Runnable接口的方式创建线程执行代码
示例:
public class Text2 {
public static void main(String[] args) {
new Thread(()->{
System.out.println("要执行的线程代码");
System.out.println("要执行的线程代码");
System.out.println("要执行的线程代码");
}).start();
}
}
- 通过Lambda表达式实现Comparator接口的方式指定排序规则
import java.util.ArrayList;
import java.util.Collections;
public class Text2 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(500);
list.add(800);
list.add(400);
list.add(200);
list.add(100);
list.add(500);
// 升序
Collections.sort(list,((Integer o1,Integer o2)->{return o1 - o2;}));
System.out.println(list); // 输出 [100, 200, 400, 500, 500, 800]
// 可以简写为:
Collections.sort(list,(( o1, o2)-> o2 - o1));// 降序
System.out.println(list); // 输出 [800, 500, 500, 400, 200, 100]
}
}
Lambda表达式省略格式
- 省略规则
- 小括号中参数类型可以省略不写
- 小括号中只有一个参数,那么小括号也可以省略
- 大括号中如果只有一条语句,那么大括号,return关键字,分号也可以省略(三个要一起省略)
Stream流
- 特点:
- 流一定要搭建好完整的函数模型,函数模型中必须要有终结方法
- Stream流不能重复操作,也就是一个Stream流只能使用一次
- Stream流不会存储数据的
- Stream流不会修改数据源
获取流方式_
- 根据集合获取流
- Collection集合中有一个获取流的方法public default Stream<E> stream();
示例:
import java.util.ArrayList;
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(500);
list.add(800);
list.add(400);
list.add(200);
list.add(100);
list.add(500);
// 获取Stream流
Stream str = list.stream();
}
- 根据Map获取流
- 根据Map集合的键获取流
- 根据Map集合的值获取流
- 根据Map集合的键值对对象获取流
示例:
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
HashMap<String,Integer> hm = new HashMap();
hm.put("张三",18);
hm.put("李四",28);
hm.put("老六",38);
hm.put("王五",48);
// 通过key键获取 Stream流
Stream str1 = hm.keySet().stream();
// 通过Values值获取 Stream流
Stream str2 = hm.values().stream();
// 通过集合的键值对对象获取 Stream流
Stream<Map.Entry<String, Integer>> str3 = hm.entrySet().stream();
}
}
- 根据数组获取流
- 使用Stream流的静态of方法
示例:
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
// 根据数组获取 Stream流
String str[] = {"张三","李四","王五"};
// 通过数组传值
Stream<String> st1 = Stream.of(str);
// 直接给值
Stream<Integer> st2 = Stream.of(12,13,14,15,16);
}
}
Stream流常用方法
终结方法: 方法的返回值类型不是Stream流,流中一定要有终结方法,否则无法执行
延迟方法: 方法的返回值类型是Stream流
常用方法_
forEach: 逐一处理流中的元素
示例:
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
Stream<Integer> st2 = Stream.of(12, 13, 14, 15, 16);
st2.forEach((t) -> System.out.println(t));
//输出
//12
//13
//14
//15
//16
}
}
count: 统计流中元素的个数
示例:
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
Stream<Integer> st2 = Stream.of(12, 13, 14, 15, 16);
// 统计个数
System.out.println(st2.count()); // 输出 5
}
}
filter: 根据条件过滤
示例:
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
Stream<String> st2 = Stream.of("王一","张三","王二","王三","李四");
// 按条件筛选
st2.filter( i -> i.startsWith("王")).forEach(i-> System.out.println(i)); // 输出 王一,王二,王三
}
}
limit: 取流中前几个元素
示例:
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
Stream<String> st2 = Stream.of("王一", "张三", "王二", "王三", "李四");
// 获取前4个元素
st2.limit(4).forEach(i -> System.out.println(i));
}
}
skip: 跳过流中前几个元素
示例:
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
Stream<String> st2 = Stream.of("王一", "张三", "王二", "王三", "李四");
// 跳过前4个元素
st2.skip(4).forEach(i -> System.out.println(i));
}
}
map: 映射\转换
示例:
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
Stream<String> st2 = Stream.of("100", "200", "300", "400", "500");
// 把String 转化成Integer格式输出
st2.map(t -> Integer.parseInt(t)).forEach(e -> System.out.print(e + 1 + " ")); // 输出 101 201 301 401 501
}
}
concat: 拼接2个流
示例:
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
// 获取流
Stream<String> stream1 = Stream.of("100", "200", "300", "400");
// 获取流
Stream<String> stream2 = Stream.of("张三", "李四", "老王","小明");
// 拼接 把两个流拼接成一个
Stream.concat(stream1,stream2).forEach(e-> System.out.println(e));
}
}
收集Stream流结果
- 收集到数组中
public statci Object[] toArray(); 把流中的元素收集到数组中
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
// 获取流
Stream<String> str = Stream.of("100", "200", "300", "400");
Object arr[] = str.toArray();
for (Object o : arr) {
System.out.println(o);
}
}
}
- 收集到集合中
-<R, A> R collect(Collector<? super T, A, R> collector);把流中的元素收集到集合中
常用方法:
stream.collect(Collectors.toList()) 收集到List集合
stream.collect(Collectors.toSet()) 收集到Set集合
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Text2 {
public static void main(String[] args) {
// 获取流
Stream<String> str = Stream.of("100", "200", "300", "400");
// 收集到Set集合
Set<String> set = str.collect(Collectors.toSet());
// 输出 [100, 200, 300, 400]
System.out.println(set);
}
}