关于线程池、Lambda表达式的概述

线程池、Lambda表达式

等待唤醒机制

线程间的通信

概念:多个线程在处理同一个资源,但是处理的动作(线程任务)却不相同,需要线程通信来解决线程之间对同一个变量的使用或操作,即是多个线程在操作同一份数据时, 避免对同一共享变量的争夺。(通过等待唤醒机制使线程有效利用资源)

等待唤醒机制

多个线程间的一种协作机制

就是在一个线程进行了规定操作后,就进入等待状态(wait()), 等待其他线程执行完他们的指定代码过后 再将 其唤醒(notify());在有多个线程进行等待时, 如果需要,可以使用 notifyAll()来唤醒所有的等待线程。

wait/notify 就是线程间的一种协作机制

等待唤醒中的方法
1.wait:线程不再活动,不参与调度.进入wait set中(不会浪费CPU资源,也不会竞争锁),此时线程状态是 Waiting.等待其他线程执行notify,通知当前对象等待的线程从wait set中释放,重新进入到调度队列中

2. notify:选取所通知对象的 wait set 中的一个线程释放 (等待最久的先释放)

3.notifyAll:释放所通知对象的 wait set 上的全部线程。
 
//就算通知了等待的线程,其线程也不能立即恢复执行,由于当初中断地方在同步块内,所有它已经不持有锁,需要再次获得锁(可能面临其他线程竞争),才能在之前调用wait方法之后的地方执行
  • ​ 如果能获取锁,线程就从 WAITING 状态变成 RUNNABLE 状态;

  • ​ 否则,从 wait set 出来,又进入 entry set,线程就从 WAITING 状态又变成 BLOCKED 状态

调用wait和notify方法要注意的细节
1.wait方法与notify方法必须由同一个锁对象调用  //因为对于的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程

2.wait方法与notify方法是属于Object类的方法的 //锁对象可以是任意对象,任意对象所属类都是继承Object类

3. wait方法与notify方法必须要在同步代码块或者是同步函数中使用 //必须通过锁对象调用这两个方法

线程池

线程池概念

线程池::一个可以容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程和销毁线程的操作,无需消耗过多资源

在这里插入图片描述

线程池的好处

1.降低资源消耗
2.提高响应速度
3.提高线程的可管理性    

线程池的使用

Java里面线程池的顶级接口是 java.util.concurrent.Executor ,但是严格意义上讲 Executor 并不是一个线程 池,而只是一个执行线程的工具。真正的线程池接口java.util.concurrent.ExecutorService

Executors类中有个创建线程池的方法:

public static ExecutorService newFixedThreadPool(int nThreads) :返回线程池对象  //创建的是有界线程池,线程个数可以指定最大数量
       

获取到了一个线程池ExecutorService 对象,定义一个使用线程池对象的方法:

public Future<?> submit(Runnable task) :获取线程池中的某一个线程对象,并执行

使用线程池中线程对象的步骤:

1.创建线程对象
 //使用线程池工厂类Executors里提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池   
2.创建Runnable接口子类对象
    //创建一个类,实现Runnable接口,重写run方法,设置线程任务
3.提交Runnable接口子类对象
    //调用ExecutorService中的方法,传递线程任务(实现类),开启线程,执行run方法
4.关闭线程(一般不做)
    //调用ExecutorService中的方法shutdown销毁线程(不建议执行)

Runnable实现类代码:

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("我要一个英语老师");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("英语老师来了: " + Thread.currentThread().getName());  //返回当前线程的名字
        System.out.println("教LOVE后,返回办公室");
    }
}

测试类代码:

public class ThreadPoolDemo {
    public static void main(String[] args) {
// 创建线程池对象
        ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
// 创建Runnable实例对象
        MyRunnable r = new MyRunnable();

// 从线程池中获取线程对象,然后调用MyRunnable中的run()
        service.submit(r);
// 再获取个线程对象,调用MyRunnable中的run()
        service.submit(r);
        service.submit(r);
// 注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。
// 将使用完的线程又归还到了线程池中
// 关闭线程池
//service.shutdown();
    }
}

Lambda表达式

java8的全新语法,使Runnable接口的匿名内部类写法可以更简单,通过Lambda表达式

传统代码

使用实现类

1.启动一个线程,需要创建Thread类的对象并调用start方法。为了指定线程内容,需要调用Thread类的构造方法:

public Thread(Runnable target)

2.为了获取Runnable接口的实现对象,该接口定义一个实现类RunnableImpl

public class RunnableImpl implements Runnable {
   @Override
   public void run() {
          System.out.println("多线程任务执行!");
      }
}

3.创建实现类对象作为Thread类的构造参数:

public class DemoThreadInitParam {
    public static void main(String[] args) {
        Runnable task = new RunnableImpl();
        new Thread(task).start();
}

使用匿名内部类

RunnableImpl 类只是为了实现 Runnable 接口而存在的,进被使用一次,所以使用匿名内部类

public class Demo01ThreadNameless {
       public static void main(String[] args) {
           new Thread(new Runnable() {
              @Override
              public void run() {
                System.out.println("多线程任务执行!");
         }
      }).start();
   }
}

语义分析

Runnable接口只有一个run方法定义:

public abstract void run();,限定了规格(函数规格)

  • 无参数:不需要任何条件就可执行
  • 无返回值:不产生任何结果
  • 代码块:方案的具体执行步骤

同样语义体现在Lambda语法

()> System.out.println("多线程任务执行!")
    /*1.前面一对小括号表示:run方法的参数(无),即不需要条件
     *2.中间的一个箭头表示:将前面的参数传递给后面的代码
     *3.后面的输出语句即:业务逻辑代码
     */
Lambda标准格式

3部分组成

  • 一些参数
  • 一个箭头
  • 一段代码

标准格式

(参数类型 参数名称)> { 代码语句 }
/*
小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
-> 是新引入的语法格式,代表指向动作。
大括号内的语法与传统方法体要求基本一致。
*/
使用Lambda标准格式(无参无返回)

举例:

定义一个学生Student接口,含有唯一的抽象方法learnEnglish无参数,无返回值

public interface Student{
     void learnEnglish();
}

在下面的代码中,请使用Lambda的标准格式调用 study方法,打印输出“小罗赶紧学英语”

public class Demo05InvokeCook {
     public static void main(String[] args) {          
}
      private static void study(Student student {
          Student.learnEnglish();
    }
}

Lambda表达

public static void main(String[] args) {
study(()> {
System.out.println("小罗赶紧学英语");
}
Lambda的参数和返回值

举例:

需求:
使用数组存储多个Person对象
对数组中的Person对象使用Arrays的sort方法通过年龄进行升序排序

//假设有一个 Person 类,含有 String name 和 String age 两个变量
// 当需要对一个对象数组进行排序时, Arrays.sort 方法需要一个 Comparator 接口实例来指定排序的规则。   

java.util.Comparator

抽象方法定义:public abstract int compare(T o1, T o2);

person类

public class Person {
     private String name;
     private int age;

     // 省略构造器、toString方法与Getter Setter
}

传统

测试类

import java.util.Arrays;
import java.util.Comparator;
   public class Demo01Comparator {
       public static void main(String[] args) {
          // 本来年龄乱序的对象数组
           Person[] array = {
           new Person("小罗", 22),
           new Person("小月", 18),
            new Person("小轩", 24) };
            // 匿名内部类
         Comparator<Person> comp = new Comparator<Person>() {
             @Override
             public int compare(Person o1, Person o2) {
               return o1.getAge() ‐ o2.getAge();
   }
};
                 Arrays.sort(array, comp); // 第二个参数为排序规则,即Comparator接口实例
              for (Person person : array) {
                     System.out.println(person);
            }
       }
}

Lambda写法

import java.util.Arrays;
        public class Demo02ComparatorLambda {
           public static void main(String[] args) {
               Person[] array = {
               new Person("小罗", 22),
               new Person("小月", 18),
               new Person("小轩", 24) };
              Arrays.sort(array, (Person a, Person b)> {
                  return a.getAge() ‐ b.getAge();
});
                 for (Person person : array) {
                     System.out.println(person);
}
}

Lambda省略格式

规则

1. 小括号内参数的类型可以省略;
2. 如果小括号内有且仅有一个参,则小括号可以省略;
3. 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
Lambda使用前提
1. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。
   //有且仅有一个抽象方法的接口,称为“函数式接口”。

2. 使用Lambda必须具有上下文推断,即是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

tem.out.println(person);
}
}




#### Lambda省略格式

**规则**:

```java
1. 小括号内参数的类型可以省略;
2. 如果小括号内有且仅有一个参,则小括号可以省略;
3. 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
Lambda使用前提
1. 使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。
   //有且仅有一个抽象方法的接口,称为“函数式接口”。

2. 使用Lambda必须具有上下文推断,即是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值