Java 进阶学习笔记day_09(线程状态、Lambda表达式、Stream流)

线程状态


  • 线程从创建到销毁的过程称为线程的生命周期,在线程的生命周期内一共有六种状态
线程状态导致状态发生条件
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);
	    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值