18.Java語言線程池和Lambda表達式

線程等待喚醒機制

1.線程間的通信:

       一個程序完成某個任務,需要多個線程協調,就需要線程之間存在“通信”,比如生產者和消費者,只有生產了才能被消費。當生產者生產完成才能告知消費者可以消費,那麼告知的過程就是線程間的通信。

2.等待與喚醒機制:

              1)."等待與喚醒機制”就是“線程間通信”的一種體現。

              2).工作形式:

                     1).一個線程做一些“準備性工作”。

          2).另一個線程做正常的工作。由於兩個線程是“無序的”,很有可能“第二個線程工作時,第一個線程的準備工作還沒

           有做好,這時就需要第二個線程要主動“等待”,然後第一個線程進入開始做準備,準備工作做好後,再喚醒第二個

            線程開始正常工作。

喚醒機制_生產者與消費者

                     線程通信_包子鋪 -----生產者生產包子,放在包子鋪,消費者到包子鋪取包子,只有生產者生產完包子通知消費者,消費者才

                                             可以到包子鋪獲取包子,否則只能無限等待

包子鋪類:

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

public class BaoZiPu{
    List<String> 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表達式的寫法

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));

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章