18.Java语言线程池和Lambda表达式

线程等待唤醒机制

1.线程间的通信:

       一个程序完成某个任务,需要多个线程协调,就需要线程之间存在“通信”,比如生产者和消费者,只有生产了才能被消费。当生产者生产完成才能告知消费者可以消费,那么告知的过程就是线程间的通信。

2.等待与唤醒机制:

              1)."等待与唤醒机制”就是“线程间通信”的一种体现。

              2).工作形式:

                     1).一个线程做一些“准备性工作”。

          2).另一个线程做正常的工作。由于两个线程是“无序的”,很有可能“第二个线程工作时,第一个线程的准备工作还没

           有做好,这时就需要第二个线程要主动“等待”,然后第一个线程进入开始做准备,准备工作做好后,再唤醒第二个

            线程开始正常工作。

唤醒机制_生产者与消费者

                     线程通信_包子铺 -----生产者生产包子,放在包子铺,消费者到包子铺取包子,只有生产者生产完包子通知消费者,消费者才

                                             可以到包子铺获取包子,否则只能无限等待

包子铺类:

import java.util.ArrayList;
import java.util.List;

public class BaoZiPu{
    List list = new ArrayList<>();
    Object obj = new Object();
    public void setBaozi(){
        synchronized (obj){
            list.add("包子");
            obj.notifyAll();
        }
    }
    public String getBao() throws InterruptedException {
        synchronized (obj){
            if(list.size() == 0){
                System.out.println("访问的线程需要等待....");
                obj.wait();
                System.out.println("访问的线程被唤醒......");
            }
            String s = list.get(0);
            list.remove(s);
            return s;

        }
        }
}

获取包子 

public class GetBaozi extends Thread{
    BaoZiPu baoZiPu;

    public GetBaozi(BaoZiPu baoZiPu) {
        this.baoZiPu = baoZiPu;
    }

    @Override
    public void run() {
        while (true){
            try {
                System.out.println(baoZiPu.getBao());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

生产包子

public class SetBaozi extends Thread {
    BaoZiPu baoZiPu;

    public SetBaozi(BaoZiPu baoZiPu) {
        this.baoZiPu = baoZiPu;
    }

    @Override
    public void run() {
        while (true) {
            baoZiPu.setBaozi();
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

 测试类:

public class Demo {
    public static void main(String[] args) {
        BaoZiPu baoZiPu = new BaoZiPu();
        GetBaozi getBaozi = new GetBaozi(baoZiPu);
        SetBaozi setBaozi = new SetBaozi(baoZiPu);
        getBaozi.start();
        setBaozi.start();
    }
}

 

线程池

存储了若干多的“线程对象”的一个“容器”。 线程池类:ExecutorService这个线程池就可以缓存大量的线程对象,并可以反复的重用它们。

1.线程池思想概述

1).对于一个线程对象“只能启动一次”,若想第二次再用,就需要再次创建一个线程对象,但如果创建线程对象很耗时,这

样如果程序中要反复的使用同一个线程,整个程序的效率就会很低。

2).线程池的思想:在程序启动时,会先创建若干多的线程对象,并存储到一个容器中,作为“线程池”。如果有需要时,取

出一个线程对象,并执行它。执行完毕,线程池会回收这个线程对象,如果再次需要,可以再次取出,并执行它。所以,

线程池中的线程对象是“可以反复重用”的。这样就避免的反复的创建线程对象,从而提高程序的执行效率。

2.线程池的使用

Java里面线程池的顶级接口是 java.util.concurrent.Executor ,但是严格意义上讲Executor 并不是一个线程池,而只是一

个执行线程的工具。真正的线程池接口是java.util.concurrent.ExecutorService

 

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

a).public static ExecutorService newFixedThreadPool(int nThreads) :返回线程池对象。(创建的是有界线程池,也就是池

中的线程个数可以指定最大数量)

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

3.线程池的特点

如果创建一个线程需要五秒钟,不用线程池,每创建一个线程就需要五秒,用了线程池,因为线程池执行后,会将此线程

对象"缓存",可以重用,那么再次创建就不需要时间。

示例:

public class MyThread extends Thread {
    public MyThread() {
        for (int i = 0; i < 5; i++) {
            System.out.println("等待中..." + (i + 1) + "秒");
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    public void run() {
        System.out.println("线程运行啦");
    }

}

测试类:

public class Demo {

    public static void main(String[] args) {

        MyThread myThread = new MyThread();

        myThread.start();

        myThread = new MyThread();

        myThread.start();
    }

}

 

Lambda表达式

1.冗余的Runnable代码

方式一是创建Runnable的实现类的对象,通过Thread的构造函数创建线程。

方式二是用Runnable的匿名内部类创建线程。

public class Demo {
    public static void main(String[] args) {
        //1.方式一:制作Runnable子类的方式
         MyRunnable myRunnable = new MyRunnable();
        Thread t = new Thread(myRunnable);
        t.start();
        //2.方式二:匿名内部类的方式
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("i = " + i);
                }
            }
        });
        t2.start();
    }
}

2.Lambda表达式的写法

18.Java语言线程池和Lambda表达式_第1张图片

3.编程思想转换及函数式编程思想概述

1).编程思想转换:将“以什么形式做”,转换为“怎样做”。

2).“函数式”编程思想:当调用的方法需要一个“接口”类型时,就可以考虑直接传入一个代替的“函数(方法)”即可,其它无用的语句可以省略。

4.Lambda表达式的使用

       1).使用前提:具备以下条件,才可以使用Lambda。

              1).首先需要的是一个“接口类型”;

              2).而且这个接口中有,且只有一个“抽象方法”--函数式接口;

       2).标准格式(三部分)

              第一部分:一对小括号--形参;

              第二部分:一个右箭头:->

              第三部分:一对大括号--方法体;

       3).标准格式的的写法

              无参       ()->{//方法体}

              有参       (int a,int b)->{//方法体}

              方法体内按照正常代码格式

5.Lambda表达式的省略格式和原则

       1).示例:

//Lambda表达式--完整格式

fun((int x, int y) -> {return x + y;}, 10, 20);

//简写的Lambda

fun((x, y) -> x + y, 10, 20);

       2).省略规则:

              1).形参:Lambda中的"形参类型”都可以省略;

                     fun((x) -> {return x * x;});

              2).形参:如果只有一个形参,形参类型和小括号都可以省略

                        (要省略小括号,必须省略数据类型)

                     fun(x -> {return x * x;});

              3).方法体:如果方法体中只有一条语句,可以应用省略规则;

                     A).有返回值:可以省略大括号、return关键字、语句后的分号

                                   (要省全省,要用全用)

                            fun(x -> x * x);

                     B).无返回值:可以省略大括号、语句后的分号;

                                   (要省全省,要用全用)

                            fun(x -> System.out.println("x = " + x));

你可能感兴趣的:(JavaSE)