2022.09.19 学习笔记

lambda表达式

sort

public class ComparatorTest {
    public static void main(String[] args) {
        Apple a1 = new Apple("red",120.33);
        Apple a2 = new Apple("red",129.33);
        Apple a3 = new Apple("red",119.33);
        List<Apple> appleList = Arrays.asList(a1,a2,a3);
        test1(appleList);
    }

    /**
     * 方式1 创建类并实现Comparator
     */
    public static void test1(List<Apple> appleList){
        appleList.sort(new AppleComparator());
        System.out.println(JSON.toJSONString(appleList));
    }

    /**
     * 方式2 匿名内部类
     */
    public static void test2(List<Apple> appleList){
        appleList.sort(new Comparator<Apple>() {
            @Override
            public int compare(Apple o1, Apple o2) {
                return o1.getWeight().compareTo(o2.getWeight());
            }
        });
    }

    /**
     * 方式3 使用Lambda表达式
     */
    public static void test3(List<Apple> appleList){
        appleList.sort(((o1, o2) -> o1.getWeight().compareTo(o2.getWeight())));
        System.out.println(JSON.toJSONString(appleList));
    }

    /**
     * 方式4 方法3改进
     */
    public static void test4(List<Apple> appleList){
        //comparing中的参数是Function的实现
        //其中返回的参数是用于排序的key
        appleList.sort(Comparator.comparing((a -> a.getWeight())));
        System.out.println(JSON.toJSONString(appleList));
    }

    /**
     * 方式5 使用方法引用
     */
    public static void test5(List<Apple> appleList){
        appleList.sort(Comparator.comparing((Apple::getWeight)));
        System.out.println(JSON.toJSONString(appleList));
    }
}

自定义lambda表达式实现接口

定义一个只有一个抽象方法的接口,其实际上是一个函数式接口,可在接口前面加上@FunctionalInterface注解进行验证。

public class LambdaTestB {
    public static void main(String[] args) {
        Fu2 fu  = a->a*5;
        System.out.println(fu.add(100));
    }
}

@FunctionalInterface
interface Fu2{
    int add(int a);
}

注意其lambda表达式的格式应该和add()一致的函数类型

内置的函数式接口

Consumer:消费型接口(void accept(T t))。有参数,无返回值 (上文forEach的参数类型就是Consumer)

Supplier:供给型接口(T get())。只有返回值,没有入参

Function<T, R>:函数型接口(R apply(T t))。一个输入参数,一个输出参数,两种类型不可不同、可以一致

Predicate:断言型接口(boolean test(T t))。输入一个参数,输出一个boolean类型得返回值

线程池

//这个属性是用来存放 当前运行的worker数量以及线程池状态的
//int是32位的,这里把int的高3位拿来充当线程池状态的标志位,后29位拿来充当当前运行worker的数量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//存放任务的阻塞队列
private final BlockingQueue<Runnable> workQueue;
//worker的集合,用set来存放
private final HashSet<Worker> workers = new HashSet<Worker>();
//历史达到的worker数最大值
private int largestPoolSize;
//当队列满了并且worker的数量达到maxSize的时候,执行具体的拒绝策略
private volatile RejectedExecutionHandler handler;
//超出coreSize的worker的生存时间
private volatile long keepAliveTime;
//常驻worker的数量
private volatile int corePoolSize;
//最大worker的数量,一般当workQueue满了才会用到这个参数
private volatile int maximumPoolSize;
处理流程

1.查看核心线程池是否已满,不满就创建一条线程执行任务,否则执行第二步。

2.查看任务队列是否已满(Blocking queue),不满就将任务存储在任务队列中,否则执行第三步。

3.查看线程池是否已满,即就是是否达到最大线程池数,不满就创建一条线程执行任务,否则就按照策略处理无法执行的任务。

线程状态切换

运行态->等待态(WAITING)

  • Object.join():把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行
    比如线程B中调用了线程A的join()方法,线程A执行完成后,线程B才会开始执行

  • Object.wait():线程进入等待状态,进入等待状态的线程需要依赖其他线程的通知(notify/notifyAll)才能够返回到运行状态

  • LockSupport.park():park函数是将当前调用Thread阻塞,而unpark函数则是将指定线程Thread唤醒。与Object类的wait/notify机制相比,

    1. park/unpark有两个优点:

      ① 以thread为操作对象更符合阻塞线程的直观定义

      ② 操作更精准,可以准确地唤醒某一个线程(notify随机唤醒一个线程,notifyAll唤醒所有等待的线程),增加了灵活性。

    2. park是等待一个许可,unpark是为某线程提供一个许可。
      如果某线程A调用park,那么除非另外一个线程调用unpark(A)给A一个许可,否则线程A将阻塞在park操作上

    3. unpark操作可以在park操作之前

    4. “许可”是不能叠加的,“许可”是一次性的:线程B连续调用了三次unpark函数,当线程A调用park函数就使用掉这个“许可”,如果线程A再次调用park,则进入等待状态

等待态->运行态

  • Object.notify()
  • Object.notifyAll()
  • LockSupport.unpark(Thread)

运行态->超时等待(TIMED_WAITING)

超时等待状态在等待状态的基础上增加了超时限制,当达到超时时间后会返回运行状态

  • Thread.sleep(long) 这里单位是millisconds,为了便于控制sleep的时间,可以使用

  • TimeUnit.SECONDS.sleep(long):TimeUnit是java.util.concurrent包下面的一个类,表示给定单元粒度的时间段,作用包括:

    1. 时间颗粒度转换

      //结果:24  
      System.out.println( TimeUnit.DAYS.toHours( 1 ) );  
      //结果:3600  
      System.out.println( TimeUnit.HOURS.toSeconds( 1 ));  
      //结果是:72  
      System.out.println( TimeUnit.HOURS.convert( 3 , TimeUnit.DAYS ) );           
      
    2. 延时

      TimeUnit.SECONDS.sleep(long);
      
  • Object.wait(long)

  • Thread.join(long)

  • LockSupport.parkNanos(long) LockSupport.parkUntil(long)

    超时等待(TIMED_WAITING)->运行态

  • Object.notify()

  • Object.notifyAll()

  • LockSupport.unpark(Thread)

运行态->阻塞态

  • 等待进入synchronized方法
  • 等待进入synchronized块

阻塞态->运行态

  • 获取到锁

安全地终止线程

  • 使用interrupt() 中断操作来终止线程
  • 通过标示位判断来终止

线程间通信

volatile

用于修饰成员变量,告知程序任何对该变量的访问均需要从共享内存中获取,并且对于它的改变必须同步刷新回共享内存,能保证所有线程对变量访问的可见性。

过多地使用会降低程序执行的效率

synchronized

用于修饰方法或者以同步块的形式来进行使用。确保多个线程在同一时刻,只能有一个线程处于方法或者同步块中,保证了线程对变量访问的可见性和排他性。

任意线程对Object的访问,首先要获取Object的监视器。如果获取失败,线程进入同步队列,状态变为Blocked,当访问Object的前驱(获得了锁的线程)释放了锁,那么该释放操作会唤醒阻塞在同步队列中的线程,使其重新尝试对监视器的获取。

等待/通知机制

  • 使用wait()、notify()、notifyAll()的时候需要先对调用对象加锁
  • 调用wait()方法后线程进入等待状态,并且释放锁
  • 其他线程调用notify()、notifyAll()之后,还需要等调用这两个方法的线程释放锁,等待线程获得了调用对象的锁之后,才会从wait()返回
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值