Java学习日志(十三): 线程池,Lambda表达式

JavaEE学习日志持续更新----> 必看!JavaEE学习路线(文章总汇)

线程池

线程池的原理

线程池:容器(集合),存储线程
当程序开始启动的时候,创建一些线程,存储到集合(LinkedList:增删快)中。
当使用线程完成线程任务的时候,我们可以从线程池中取出线程使用。

Thread t = linked.removeFirst();

使用完线程,需要把线程再归还给线程池

linked.addLast(t);

好处:避免了线程的重复创建和销毁,提高了程序效率

在这里插入图片描述

线程池的基本使用

在JDK1.5之后,java内置了线程池技术,可以直接使用

java.util.concurrent.Executors类生产线程池的工厂类
静态方法
static ExecutorService newFixedThreadPool​(int nThreads)
创建一个线程池,该池重用在共享的无界队列中运行的固定数量的线程。

  • 参数:
    int nThreads:线程池中线程的数量
  • 返回值:
    ExecutorService:是一个线程池接口
    返回的是ExecutorService的实现类对象,可以使用ExecutorService接口来接收这个实现类对象(多态)

java.util.concurrent.ExecutorService
Future<?> submit​(Runnable task) 提交Runnable任务以执行并返回表示该任务的Future。
void shutdown() 关闭,销毁线程池

注意:若销毁线程池之后,再使用线程池,会出现RejectedExecutionException异常

示例1:使用线程池执行Runnable线程任务

public class Demo01 {
    public static void main(String[] args) {
        //1.使用线程池工厂类Executors中的静态方法newFixedThreadPool,生产一个指定线程数量的线程池
        ExecutorService es = Executors.newFixedThreadPool(2);
        //2.使用线程池ExecutorService中的方法submit,提交线程任务
        es.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程执行了线程任务");//pool-1-thread-2线程执行了线程任务
            }
        });

        es.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程执行了线程任务");//pool-1-thread-1线程执行了线程任务
            }
        });

        es.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程执行了线程任务");//pool-1-thread-2线程执行了线程任务
            }
        });
        //void shutdown() 关闭,销毁线程池,销毁之后线程池消失,不能再使用
        es.shutdown();
        //再使用线程池,会报异常,RejectedExecutionException
        /*es.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"线程执行了线程任务");//pool-1-thread-2线程执行了线程任务
            }
        });*/
    }
}

示例2:使用线程池执行Callable接口提交的线程任务
java.util.concurrent.ExecutorService
Future<T> submit​(Callable<T> task) 提交值返回任务以执行并返回表示任务的挂起结果的Future。

  • 参数:
    传递线程任务,submit方法会在线程池中获取一个线程,用来执行线程任务。使用完毕把线程归还给线程池

java.util.concurrent.Callable<泛型>接口:用来设置线程任务
抽象方法:
V call()返回一个和接口类型相同的值
可以使用Future接口中的方法V get()获取Callable接口的返回值

public class Demo02 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1.使用线程池工厂类Executors中的静态方法newFixedThreadPool,生产一个指定线程数量的线程池
        ExecutorService es = Executors.newFixedThreadPool(2);
        //2.使用线程池ExecutorService中的方法submit,提交线程任务
        Future<Integer> f1 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {

                return new Random().nextInt(100);//[0,100)
            }
        });
        System.out.println(f1);//java.util.concurrent.FutureTask@6e8cf4c6
        //使用Future接口中的方法get获取Callable接口的返回值
        // V get() 如果需要等待计算完成,然后检索其结果。
        System.out.println(f1.get());//[0,100)
    }
}

线程池练习

使用Callable返回一个线程任务:获取1到指定整数之间的和
返回:如1-100

代码实现:

public class Demo03Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1.使用线程池工厂类Executors中的静态方法newFixedThreadPool,生产一个指定线程数量的线程池
        ExecutorService ex = Executors.newFixedThreadPool(2);
        //使用键盘输入获取整数
        System.out.println("请输入一个整数");
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        //2.使用线程池ExecutorService中的方法submit,提交线程任务
        Future<Integer> f = ex.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                //获取1到指定整数之间的和
                int sum = 0;
                for (int i = 1; i <= a; i++) {
                    sum += i;
                }
                return sum;
            }
        });
        System.out.println(f.get());
    }
}

Lambda表达式

Lambda表达式的格式

()->{} 一些参数,一个箭头,一段代码

详细说明:
():接口中抽象方法的参数 (int a,int b) (String s)
->:传递,把参数传递给方法体使用
{}:重写接口抽象方法的方法体

示例1:匿名内部类与Lambda表达式的区别

public class Demo01 {
    public static void main(String[] args) {
        //使用匿名内部类,简化程序
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类");
            }
        }).start();
        //使用Lambda表达式,简化匿名内部类
        //new Runnable() {
        //            @Override
        //            public void run
        //上述代码被简化了
        new Thread(()->{
            System.out.println("Lambda表达式");
        }).start();
    }
}

示例2:简化有参数有返回值的方法
需求:

  1. 定义一个数组。类型使用Person,存储Person对象
  2. 使用数组工具类Arrays中的方法sort,对象Person按照年龄降序排序

java.util.Arrays:

static <T> void sort​(T[] a, Comparator<? super T> c)
根据指定比较器引发的顺序对指定的对象数组进行排序。

public class Demo02 {
    public static void main(String[] args) {
        //1. 定义一个数组。类型使用Person,存储Person对象
        Person[] arr = {
                new Person("aaa", 18),
                new Person("bbb", 20),
                new Person("ccc", 15),
        };
        // 2. 使用数组工具类Arrays中的方法sort,对象Person按照年龄降序排序
        //匿名内部类
        Arrays.sort(arr, new Comparator<Person>() {
            @Override
            public int compare(Person o1 , Person o2) {
                //降序
                return o2.getAge()-o1.getAge();
            }
        });
        //使用Lambda表达式,简化匿名内部类
        Arrays.sort(arr,(Person o1 , Person o2)->{
            return o2.getAge()-o1.getAge();
        });
        //遍历数组
        for (Person p : arr) {
            System.out.println(p);
        }

    }
}
~

Lambda表达式的使用前提

  1. 简化的接口必须有且仅有一个抽象方法
  2. 可推导,可省略
    可以推导出Lambda重写的就是唯一的抽象方法,所以可以省略匿名内部类

Lambda表达式简化格式的省略规则

  • ():括号中的参数,数据类型是可以省略的 (int a,int b)–>(a,b)
    接口中只有一个抽象方法,而方法的参数数据类型是固定的,所以可以推导出来,可省略
  • ():括号中的参数,只有一个,那么数据类型和括号都可以省略 (String s)–>s
    括号中没有参数,括号不能省略
  • {}:大括号中的方法体,无论是否有返回值,如果只有一行语句,那么{} return ; 都可以省略,但是必须一起省略

示例1:
Lambda表达式

new Thread(()->{
    System.out.println("Lambda表达式");
}).start();

简化Lambda表达式

//简化Lambda表达式
new Thread(()-> System.out.println("Lambda表达式")).start();

示例2:
Lambda表达式

Arrays.sort(arr, (Person o1, Person o2) -> {
    return o2.getAge() - o1.getAge();
});

简化Lambda表达式

Arrays.sort(arr, (o1, o2) -> o2.getAge() - o1.getAge());

自定义接口使用Lambda表达式

自定义一个ABC接口,定义一个静态方法method

public interface ABC {
    public abstract void method(int a);
}

使用匿名内部类,Lambda表达式,简化Lambda表达式调用method方法

public class Demo04 {
    /*
        定义一个方法,参数使用ABC接口
     */
    public static void show(ABC abc,int a){
        abc.method(a);
    }
    public static void main(String[] args) {
    //匿名内部类
        show(new ABC() {
            @Override
            public void method(int a) {
                System.out.println(a);
            }
        },10);
    //Lambda表达式
        show((int a)->{
            System.out.println(a);
        },10);
    //简化Lambda表达式
        show((int a)-> System.out.println(a),10);
    }
}~
发布了17 篇原创文章 · 获赞 17 · 访问量 3182

猜你喜欢

转载自blog.csdn.net/Sakuraaaaaaa/article/details/104246531
今日推荐