Java之線程池和Lambda表達式

線程池和lambda表達式

學習線程池和lambda表達式的理解java

補充一個知識點(單例設計模式)

在多線程中,咱們只須要一個任務類,爲了防止建立多個任務類,這個時候就須要用到單例模式,單例模式有兩種設計:編程

  1. 延遲加載(懶漢式)
    • 私有構造方法
    • 建立本類對象,但不初始化
    • 建立靜態方法進行初始化對象並返回
  2. 當即加載(餓漢式)
    • 私有構造方法
    • 建立本類的對象並初始化(私有的)
    • 建立靜態方法獲取本類對象

下面用代碼作個實例:設計模式

package com.wzlove.single;

/**
 * 延遲加載(懶漢式)
 *  1.私有構造方法
 *  2.建立本類對象,但不初始化
 *  3.建立靜態方法進行初始化對象並返回
 *
 *  優勢:
 *      使用到類的對象纔會加載,不消耗內存
 *  缺點:
 *      可能會出現線程安全問題,可是可使用同步代碼塊消除這個安全問題
 * @author WZLOVE
 * @create 2018-07-19 10:36
 */
public class DeplayedSingle {

    // 私有構造方法
    private DeplayedSingle(){}

    // 建立本類對象,不初始化
    private  static DeplayedSingle instance ;

    // 靜態方法初始化
    public static DeplayedSingle getInstance(){
        synchronized (DeplayedSingle.class){
            if(instance == null){
                instance = new DeplayedSingle();
            }
        }
        return instance;
    }
}



package com.wzlove.single;

/**
 * 當即加載(餓漢式)
 *  1.私有構造方法
 *  2.建立本類的對象並初始化(私有的)
 *  3.建立靜態方法獲取本類對象
 *
 *  優勢:
 *      保證的線程的安全,沒有線程安全問題
 *  缺點:
 *      使用類就會加載,比較消耗內存
 * @author WZLOVE
 * @create 2018-07-19 10:37
 */
public class ImmediateSingle {

    private ImmediateSingle(){}

    private static ImmediateSingle instance = new ImmediateSingle();

    public static ImmediateSingle getInstance(){
        return instance;
    }
}

線程池

概述

線程池其實就是一個容納多個線程的容器,其中的線程能夠反覆使用,省去了頻繁建立線程對象的操做,
無需反覆建立線程而消耗過多資源。做用是節省資源,原理是容器.數組

使用線程池的好處是減小在建立和銷燬線程上所花的時間以及系統資源的開銷,解決資源不足的問題.若是不使用線程池,
有可能形成系統建立大量同類線程而致使消耗完內存或者"過分切換"的問題.安全

建立線程池:多線程

  • public static ExecutorService newFixedThreadPool(int nThreads) :返回線程池對象。(建立的是有界線
    程池,也就是池中的線程個數能夠指定最大數量)
  • public Future<?> submit(Runnable task) :獲取線程池中的某一個線程對象,並執行
  • Future接口:用來記錄線程任務執行完畢後產生的結果。線程池建立與使用。

步驟:ide

  • 使用線程池的工廠類Executors裏面提供靜態方法newFixedThreadPool生產一個指定線程數量的線程池
  • 建立一個類,實現Runnable接口,重寫run方法,設置線程任務
  • 調用ExecutorService中的方法submit,傳遞線程任務(實現類),開啓線程(前提是線程池中有線程可用),執行run方法
  • 調用ExecutorService中的shutdown方法銷燬線程池(不建議執行)

補充線程的建立

建立線程的第三種方式(這種方式不多見)函數式編程

package com.wzlove.executor;

import java.util.ArrayList;
import java.util.concurrent.Callable;

/**
 * 線程的第三種建立方法
 *  Callable有返回值而且能夠拋出異常
 * @author WZLOVE
 * @create 2018-07-18 14:14
 */
public class CallableImpl implements Callable<String> {

    private static ArrayList<String> arrayList = new ArrayList<>();

    static{
        arrayList.add("1");
    }

    @Override
    public String call() throws Exception {
        return Thread.currentThread().getName();
    }
}



package com.wzlove.executor;

import java.util.concurrent.*;

/**
 * 測試線程的第三中建立方式
 *
 * @author WZLOVE
 * @create 2018-07-18 14:14
 */
public class Demo {

    public static void main(String[] args) {
        // 建立實現Callable的實現類對象
        Callable<String> callable = new CallableImpl();
        // 建立FutureTask,並傳遞Callable接口的實現類對象
        FutureTask task = new FutureTask(callable);
        // 建立線程池對象
        // ExecutorService executor = Executors.newSingleThreadExecutor();
        ExecutorService executor = Executors.newFixedThreadPool(3);
        executor.submit(callable);
        // 執行線程
        executor.execute(task);

        try {
            System.out.println(task.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }


}

Lambda表達式

lambda體現的是一種函數式編程的思想, 它強調的是作什麼,而不是以什麼形式作。函數

使用前提

  • 使用Lambda必須具備接口,且要求接口中有且僅有一個抽象方法。不管是JDK內置的Runnable 、Comparator 接口仍是自定義的接口,只有當接口中的抽象方法存在且惟一時,纔可使用Lambda。
  • 使用Lambda必須具備上下文推斷。也就是方法的參數或局部變量類型必須爲Lambda對應的接口類型,才能使用Lambda做爲該接口的實例。

有且僅有一個抽象方法的接口,稱爲「函數式接口」。學習

Lambda標準格式

Lambda省去面向對象的條條框框,格式由3個部分組成:

  • 一些參數
  • 一個箭頭
  • 一段代碼

Lambda表達式的標準格式爲:

(參數類型 參數名稱) ‐> { 代碼語句 }

格式說明:

  • 小括號內的語法與傳統方法參數列表一致:無參數則留空;多個參數則用逗號分隔。
  • -> 是新引入的語法格式,表明指向動做。
  • 大括號內的語法與傳統方法體要求基本一致。

線程匿名內部類的轉化(無參無返回值)

實現Runnable接口的匿名內部類的實現:

public class Demo01Runnable {
    public static void main(String[] args) {
        // 匿名內部類
        Runnable task = new Runnable() {
            @Override
            public void run() { // 覆蓋重寫抽象方法
                System.out.println("多線程任務執行!");
            }
        };
        new Thread(task).start(); // 啓動線程
    }
}

代碼分析

  • Thread 類須要Runnable 接口做爲參數,其中的抽象run 方法是用來指定線程任務內容的核心;
  • 爲了指定run 的方法體,不得不須要Runnable 接口的實現類;
  • 爲了省去定義一個RunnableImpl 實現類的麻煩,不得不使用匿名內部類;
  • 必須覆蓋重寫抽象run 方法,因此方法名稱、方法參數、方法返回值不得再也不寫一遍,且不能寫錯;
  • 而實際上,彷佛只有方法體纔是關鍵所在。

使用Lambda進行簡化:

public class Demo01Runnable {
    public static void main(String[] args) {
         new Thread(()->System.out.println("多線程任務執行!")).start(); // 啓動線程
    }
}

比較器內部類的轉化(有參有返回值)

使用比較器舉個例子:

// 建立數組
Integer[] arr = {1,8,3,4,9,2,5};

// 匿名內部類實現數組升序排序
Arrays.sort(arr,new Comparator<Integer>(){

    @Override
    public int compare(Integer o1, Integer o2) {
        return 0;
    }
});

// 使用lambda進行數組的升序排序
Arrays.sort(arr,( a, b)->{ return a - b ;});

Lambda表達式的省略規則

在Lambda標準格式的基礎上,使用省略寫法的規則爲:

  1. 小括號內參數的類型能夠省略;
  2. 若是小括號內有且僅有一個參,則小括號能夠省略;
  3. 若是大括號內有且僅有一個語句,則不管是否有返回值,均可以省略大括號、return關鍵字及語句分號。

雖然有省略寫法,可是我感受這個有點靈活,因此不建議省略,由於代碼是給別人看的,省略的話感受別人看起來會有點費勁.

相關文章
相關標籤/搜索