多線程技術講解---持續更新

多線程技術講解

傳統線程技術的回顧

1. 多線程的創建(兩種)

  1. 通過創建線程對象,複寫run(),通過start()調用該線程。

本質是繼承

Thread thread = new Thread(){
     	@Override
        public void run() {...}
    };
 thread.start();
  1. 通過有參構造創建線程對象,複寫run(),通過start()調用該線程。

本質是接口實現Runnable

 Thread  thread2 = new Thread(new Runnable() {
           @Override
           public void run() {...}
 });
thread2.start();
  • 源碼
  • 首先進入構造方法中看見init方法
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述

在這裏插入圖片描述
通過對成員變量的target的賦值,就能實現多線程。

2. 線程池的創立

傳統的線程創建,壽命只有從線程對象的確定,以及到線程代碼的結束,如果一個程序需要不同的時間,創建大量不同的線程,用上述的兩種方式創建線程,太過於消耗內存資源。由此引入新的的技術

  • 線程池技術

線程池的創立都是通過Executors創建,通過代理實現不同類型線程池的創建,
線程池都是通過不同的隊列的實現,(LinkedBlockingQueue,SynchronousQueue)

//        固定線程數
 ExecutorService threadPool = Executors.newFixedThreadPool(3);
//        根據任務調度線程數(首選,當它回收舊線程時,停止創建新線程,在使用出問題時,才使用newFixedThreadPool)
 ExecutorService threadPool = Executors.newCachedThreadPool();
//       單線程池像是newFixedThreadPool(1);在處理單線程同步問題的時候,可以減少對同步複雜性,因爲只有一個線程執行,就不存在同步的可能
ExecutorService threadPool = Executors.newSingleThreadExecutor();

常用的API

  • execute(Runnable command ) 線程調用線程池資源的核心
  • Thread.CurrentThread()獲得當前線程對象
  • shutdownNow()
  • shutdown();
    例子
ExecutorService threadPool = Executors.newSingleThreadExecutor();
       for (int i = 0; i < 10; i++) {
           final int task = i;
           threadPool.execute(new Runnable() {
               @Override
               public void run() { }
               }
           });
       }
       System.out.println("shutdown");
       threadPool.shutdownNow();
2.1 從任務中的返回值
  • Runnable是執行工作的獨立任務,但是它不返回值,如希望在任務完成時能返回一個值,那麼可以實現Callable接口而不是Runnable接口。Callable是一種具有類型參數的泛型,它的類型參數表示的是從call()而不是run()中返回的值,並且使用ExecutorService.submit()方法調用它
class TaskWithResult implements Callable<String>{
	private int id;
	public TaskWithResult(int id){
		this.id = id;
	}
	public String call(){
		return "result of TaskWithResult"+id;
	}
}
public class CallableDemo{
	public static void main(String[] args){
		ExecutorService exec = Executors.newCacheThreadPool();
		List<Future<String>> result  = new ArrayList<>();
		for(int i  = 0;i<10;i++){
			result.add(exec.submit(new TaskWithResult(1)));
		}
		for(Future<String> fs : result){
			try{
				System.out.println(fs.get());
			}catch(Exception e){
				e.printStackTrace();
			}finally{
				exec.shutdown();
			}
		}
	}
}
  • submit()方法會產生Future對象,它用Callable返回結果的特定類型進行了參數化,可以用isDone()查詢Future是否完成,若完成,那麼就有一個結果,通過get()獲取,若未完成,直接用get()方法獲取,則會阻塞,直至結果就緒。 一般先用isDone()判斷是否完成,再用get
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章