一、java多線程基礎

多線程的概念

進程是程序運行的實例。啓動一個java程序其實就是啓動了一個jvm的進程。進程是程序向操作系統申請資源(內存空間、文件句柄等)的基本單位。

線程是進程中可以獨立執行的最小單位。

進程和線程的關係,可以比喻成一個項目組和組員的關係。項目組完成一個項目需要需求,開發,測試。這些往往都是並行的。需要需求,開發和測試人員協作完成。他們共享項目組的資源,如需求文檔,功能代碼等。

爲什麼需要線程

  1. 提高cpu的利用率。因爲cpu的執行速率是遠遠高於io操作的。如果單線程運行,遇到io操作,系統會一直等待io完成再往下執行。這段io操作的時間內浪費了cpu的性能。
  2. 提高響應速率。爲了用戶的體驗,在使用GUI軟件時,一個慢的IO操作不至於會使軟件"凍住"。
  3. 充分利用多核。對應已經普及的多核計算機,多線程可以重複利用其性能。

java中的線程

java中的線程是通過java.lang.Thread類來實現。一個Thread或其子類就是一個線程。

創建線程

創建執行線程的方式有三種:

Thread類的構造函數大概可以分爲要Runnable和不需要Runnable兩種。 Thread()和 Thread(Runnable)。所以可以根據這兩種方式來創建一個線程。

  1. 繼承Thread
    //1.繼承Thread類
    class ThreadDemo extends Thread{
		
        //2.重寫run方法。
		public void run() {
			// 業務邏輯
		}
	}
	
	public static void main(String[] args) {
        //new 一個Thread對象
		Thread thread = new ThreadDemo();
        //調用start方法啓動一個線程。線程啓動後會執行run方法。
		thread.start();
	}

  1. 實現Runnable接口
    //1.實現Runnable類
    class RunnableDemo implements Runnable{
        //2.實現run方法
		public void run() {
			// 業務邏輯
		}
		
	}
	
	public static void main(String[] args) {
	    //new 一Runnable實現類
		Runnable run  = new RunnableDemo();
		//通過Runnable構造Thread
		Thread thread2 = new Thread(run);
		//啓動線程
		thread2.start();
	}

上面兩種線程都沒有返回值,jdk1.5後出現了callable能創建具有返回值的線程。

    //實現Callable接口
    class CallableDemo implements Callable<String>{
        //實現call方法
		public String call() throws Exception {
			return "callable";
		}
		
	}
	public static void main(String[] args) {
	
	//callable有兩種使用方式:
	
	//1.通過線程池
	    //創建線程池
    	ExecutorService threadService = Executors.newSingleThreadExecutor();
    	//提交callable任務
		Future<String> submit = threadService.submit(new CallableDemo());
		//阻塞獲取返回值
		String object = submit.get();
		System.out.println(object);
		
	//2. 通過FutureTask
	  FutureTask<String> task1 = new FutureTask<String>(new CallableDemo() {
		});
      Thread thread1 = new Thread(task1);
      thread1.start();
      System.out.println(task1.get());
    }

三種創建線程方式的差異

callable和runnable除了callable可以有返回值,其他的都一樣。實際上callable最終會被構造成一個實現Runnable結構的類。例如上面的FutureTask。

主要分析Runnable方式和繼承Thread這兩種方式。

  1. 繼承Thread是通過繼承的方式,實現Runnable是一種組合的方式。組合相對於繼承更加低耦合和靈活。《Effictive java》中也提到複合優先於繼承的觀點。

  2. 實現Runnable的方式,容易線程間實現資源的共享。因爲一個Runnable對象可以用來創建多個線程。對象的成員變量被多個線程共享。這也使得我們要注意線程安全問題。

線程的屬性

屬性 作用
編號(ID) 用於標識不同線程
名稱(Name) 用於區分不同線程 默認:"thread-0" .可以設置。
線程類別(Daemon) 可以設置守護線程。主線程結束,守護線程也會結束
優先級(Priority) 可以設置線程優先級,1-10.默認5.

線程的狀態

借圖: image

狀態 說明
創建(New) 線程被創建未啓動。java中就是還沒調用start方法之前
可運行(Runnable) 該狀態下有兩種情況,一種是獲取到cpu的時間片
阻塞(BLOCKED) 發起阻塞IO或者爭取獨佔鎖資源。該狀態不佔用cpu
等待(Waiting) 執行特定的方法會,等待其他線程喚醒
有時限等待(Timed Waiting) 和Waiting狀態類似,但是Timed Waiting是有時限的,指定時間到會結束等待狀態
消亡(Terminated) run方法執行完畢或者發生異常。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章