Java多線程實現方式Callable和線程池


最近項目使用原生的多線程使用方式,有點遺忘,趕緊寫個demo溫習一下。

一、Executors

在Java用有一個Executors工具類,可以為我們創建一個線程池,其本質就是new了一個ThreadPoolExecutor對象。

建議使用較為方便的 Executors 工廠方法來創建線程池。

Executors.newCachedThreadPool()(無界線程池,可以進行自動線程回收)
Executors.newFixedThreadPool(int)(固定大小線程池)
Executors.newSingleThreadExecutor()(單個后台線程)
Executors.newScheduledThreadPool() (支持計划任務的線程池)

package hanwl.juc.day2;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/*
 * 一、線程池:提供了一個線程隊列,隊列中保存着所有等待狀態的線程。避免了創建與銷毀額外開銷,提高了響應的速度。
 * 
 * 二、線程池的體系結構:
 *     java.util.concurrent.Executor : 負責線程的使用與調度的根接口
 *         |--**ExecutorService 子接口: 線程池的主要接口
 *             |--ThreadPoolExecutor 線程池的實現類
 *             |--ScheduledExecutorService 子接口:負責線程的調度
 *                 |--ScheduledThreadPoolExecutor :繼承 ThreadPoolExecutor, 實現 ScheduledExecutorService
 * 
 * 三、工具類 : Executors 
 * ExecutorService newFixedThreadPool() : 創建固定大小的線程池
 * ExecutorService newCachedThreadPool() : 緩存線程池,線程池的數量不固定,可以根據需求自動的更改數量。
 * ExecutorService newSingleThreadExecutor() : 創建單個線程池。線程池中只有一個線程
 * 
 * ScheduledExecutorService newScheduledThreadPool() : 創建固定大小的線程,可以延遲或定時的執行任務。
 */
public class TestThreadPool {
    
    public static void main(String[] args) throws Exception {
        //1. 創建線程池
        ExecutorService pool = Executors.newFixedThreadPool(5);
        
        List<Future<Integer>> list = new ArrayList<>();
        
        for (int i = 0; i < 10; i++) {
            Future<Integer> future = pool.submit(new Callable<Integer>(){

                @Override
                public Integer call() throws Exception {
                    int sum = 0;
                    
                    for (int i = 0; i <= 100; i++) {
                        sum += i;
                    }
                    
                    return sum;
                }
                
            });

            list.add(future);
        }
        
        pool.shutdown();
        
        for (Future<Integer> future : list) {
            System.out.println(future.get());
        }
        
        
        
        /*ThreadPoolDemo tpd = new ThreadPoolDemo();
        
        //2. 為線程池中的線程分配任務
        for (int i = 0; i < 10; i++) {
            pool.submit(tpd);
        }
        
        //3. 關閉線程池
        pool.shutdown();*/
    }
    
//    new Thread(tpd).start();
//    new Thread(tpd).start();

}

class ThreadPoolDemo implements Runnable{

    private int i = 0;
    
    @Override
    public void run() {
        while(i <= 100){
            System.out.println(Thread.currentThread().getName() + " : " + i++);
        }
    }
    
}
package hanwl.juc.day2;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class TestScheduledThreadPool {

    public static void main(String[] args) throws Exception {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
        
        for (int i = 0; i < 5; i++) {
            Future<Integer> result = pool.schedule(new Callable<Integer>(){

                @Override
                public Integer call() throws Exception {
                    int num = new Random().nextInt(100);//生成隨機數
                    System.out.println(Thread.currentThread().getName() + " : " + num);
                    return num;
                }
                
            }, 1, TimeUnit.SECONDS);
            
            System.out.println(result.get());
        }
        
        pool.shutdown();
    }
    
}

 

二、Callable

 

Callable接口代表一段可以調用並返回結果的代碼;Future接口表示異步任務,是還沒有完成的任務給出的未來結果。所以說Callable用於產生結果,Future用於獲取結果。

Callable接口使用泛型去定義它的返回類型。Executors類提供了一些有用的方法在線程池中執行Callable內的任務。由於Callable任務是並行的(並行就是整體看上去是並行的,其實在某個時間點只有一個線程在執行),我們必須等待它返回的結果。 
java.util.concurrent.Future對象為我們解決了這個問題。在線程池提交Callable任務后返回了一個Future對象,使用它可以知道Callable任務的狀態和得到Callable返回的執行結果。Future提供了get()方法讓我們可以等待Callable結束並獲取它的執行結果。

步驟: 

  1. 創建實體類,實現Callable接口
  2. 實現接口中的call()方法
  3. 利用 ExecutorService線程池對象 的 <T> Future<T> submit(Callable<T> task()方法提交該Callable接口的線程任務。
// 創建線程池
ExecutorService pool = Executors.newFixedThreadPool(2);
// 可以執行Runnable對象或者Callable對象代表的線程
Future<Integer> f1 = pool.submit(new MyCallable(100));
Future<Integer> f2 = pool.submit(new MyCallable(200));

// V get()
Integer i1 = f1.get();
Integer i2 = f2.get();

System.out.println(i1);
System.out.println(i2);
// 結束
pool.shutdown();

public class MyCallable implements Callable<Integer> {

    private int number;
    public MyCallable(int number) {
        this.number = number;
    }
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int x = 1; x <= number; x++) {
            sum += x;
        }
        return sum;
    }

}

 利用匿名內部類方式

ExecutorService service = Executors.newSingleThreadExecutor();
         Future<String> future = service.submit(new Callable() {
             @Override
             public String call() throws Exception {
                 return "通過實現Callable接口";
             }
         });
         try {
             String result = future.get();
             System.out.println(result);
         } catch (InterruptedException e) {
             e.printStackTrace();
         } catch (ExecutionException e) {
             e.printStackTrace();
         }

  Lambda表達式方式

public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //使用Executors工廠類創建一個單線程池
        ExecutorService es =  Executors.newSingleThreadExecutor();
        //使用這個單線程提交一個Callable接口線程服務,返回值為String
        //Callable接口是一個函數式接口,Java8開始可以直接使用Lambda表達式表示
        //其內部實現了call()方法  V call() throws Exception;
        //並得到該結果值打印
        System.out.println( es.submit(()->"使用lambda表達式的Callable接口").get());
        es.shutdown(); //關閉該線程池
    }

}

  

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM