多執行緒三分鐘就可以入個門了!

Java3y發表於2019-02-28

前言

之前花了一個星期回顧了Java集合:

在寫文章之前通讀了一遍《Java 核心技術 卷一》的併發章節和《Java併發程式設計實戰》前面的部分,回顧了一下以前寫過的筆記。從今天開始進入多執行緒的知識點咯~

之前在學習Java基礎的時候學多執行緒基礎還是挺認真的,可是在後面一直沒有回顧它,久而久之就把它給忘掉得差不多了..在學習JavaWeb上也一直沒用到多執行緒的地方(我做的東西太水了...)。

由於面試這一部分是佔很大比重的,並且學習多執行緒對我以後的提升也是很有幫助的(自以為)。

我其實也是相當於從零開始學多執行緒的,如果文章有錯的地方還請大家多多包含,不吝在評論區下指正呢~~

一、初識多執行緒

1.1介紹程式

講到執行緒,又不得不提程式了~

程式我們估計是很瞭解的了,在windows下開啟工作管理員,可以發現我們在作業系統上執行的程式都是程式:

多執行緒三分鐘就可以入個門了!

程式的定義:

程式是程式的一次執行,程式是一個程式及其資料在處理機上順序執行時所發生的活動,程式是具有獨立功能的程式在一個資料集合上執行的過程,它是系統進行資源分配和排程的一個獨立單位

  • 程式是系統進行資源分配和排程的獨立單位。每一個程式都有它自己的記憶體空間和系統資源

1.2回到執行緒

那系統有了程式這麼一個概念了,程式已經是可以進行資源分配和排程了,為什麼還要執行緒呢

為使程式能併發執行,系統必須進行以下的一系列操作:

  • (1)建立程式,系統在建立一個程式時,必須為它分配其所必需的、除處理機以外的所有資源,如記憶體空間、I/O裝置,以及建立相應的PCB;
  • (2)撤消程式,系統在撤消程式時,又必須先對其所佔有的資源執行回收操作,然後再撤消PCB;
  • (3)程式切換,對程式進行上下文切換時,需要保留當前程式的CPU環境,設定新選中程式的CPU環境,因而須花費不少的處理機時間。

多執行緒三分鐘就可以入個門了!

可以看到程式實現多處理機環境下的程式排程,分派,切換時,都需要花費較大的時間和空間開銷

引入執行緒主要是**為了提高系統的執行效率,減少處理機的空轉時間和排程切換的時間,以及便於系統管理。**使OS具有更好的併發性

  • 簡單來說:程式實現多處理非常耗費CPU的資源,而我們引入執行緒是作為排程和分派的基本單位(取代程式的部分基本功能**【排程】**)。

那麼執行緒在哪呢??舉個例子:

多執行緒三分鐘就可以入個門了!

也就是說:在同一個程式內又可以執行多個任務,而這每一個任務我就可以看出是一個執行緒

  • 所以說:一個程式會有1個或多個執行緒的

1.3程式與執行緒

於是我們可以總結出:

  • 程式作為資源分配的基本單位
  • 執行緒作為資源排程的基本單位,是程式的執行單元,執行路徑(單執行緒:一條執行路徑,多執行緒:多條執行路徑)。是程式使用CPU的最基本單位。

執行緒有3個基本狀態

  • 執行、就緒、阻塞

執行緒有5種基本操作

  • 派生、阻塞、啟用、 排程、 結束

多執行緒三分鐘就可以入個門了!

執行緒的屬性:

  • 1)輕型實體;
  • 2)獨立排程和分派的基本單位;
  • 3)可併發執行;
  • 4)共享程式資源。

執行緒有兩個基本型別

    1. 使用者級執行緒:管理過程全部由使用者程式完成,作業系統核心心只對程式進行管理。
    1. 系統級執行緒(核心級執行緒):由作業系統核心進行管理。作業系統核心給應用程式提供相應的系統呼叫和應用程式介面API,以使使用者程式可以建立、執行以及撤消執行緒。

多執行緒三分鐘就可以入個門了!

值得注意的是:多執行緒的存在,不是提高程式的執行速度。其實是為了提高應用程式的使用率,程式的執行其實都是在搶CPU的資源,CPU的執行權。多個程式是在搶這個資源,而其中的某一個程式如果執行路徑比較多,就會有更高的機率搶到CPU的執行權

1.4並行與併發

並行:

  • 並行性是指同一時刻內發生兩個或多個事件。
  • 並行是在不同實體上的多個事件

併發:

  • 併發性是指同一時間間隔內發生兩個或多個事件。
  • 併發是在同一實體上的多個事件

由此可見:並行是針對程式的,併發是針對執行緒的

1.5Java實現多執行緒

上面說了一大堆基礎,理解完的話。我們回到Java中,看看Java是如何實現多執行緒的~

Java實現多執行緒是使用Thread這個類的,我們來看看Thread類的頂部註釋

多執行緒三分鐘就可以入個門了!

通過上面的頂部註釋我們就可以發現,建立多執行緒有兩種方法:

  • 繼承Thread,重寫run方法
  • 實現Runnable介面,重寫run方法

1.5.1繼承Thread,重寫run方法

建立一個類,繼承Thread,重寫run方法


public class MyThread extends Thread {

	@Override
	public void run() {
		for (int x = 0; x < 200; x++) {
			System.out.println(x);
		}
	}

}
複製程式碼

我們呼叫一下測試看看:


public class MyThreadDemo {
	public static void main(String[] args) {
		// 建立兩個執行緒物件
		MyThread my1 = new MyThread();
		MyThread my2 = new MyThread();

		my1.start();
		my2.start();
	}
}
複製程式碼

多執行緒三分鐘就可以入個門了!

1.5.2實現Runnable介面,重寫run方法

實現Runnable介面,重寫run方法


public class MyRunnable implements Runnable {

	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(x);
		}
	}

}
複製程式碼

我們呼叫一下測試看看:


public class MyRunnableDemo {
	public static void main(String[] args) {
		// 建立MyRunnable類的物件
		MyRunnable my = new MyRunnable();

		Thread t1 = new Thread(my);
		Thread t2 = new Thread(my);

		t1.start();
		t2.start();
	}
}
複製程式碼

結果還是跟上面是一樣的,這裡我就不貼圖了~~~

1.6Java實現多執行緒需要注意的細節

不要將run()start()搞混了~

run()和start()方法區別:

  • run():僅僅是封裝被執行緒執行的程式碼,直接呼叫是普通方法
  • start():首先啟動了執行緒,然後再由jvm去呼叫該執行緒的run()方法。

jvm虛擬機器的啟動是單執行緒的還是多執行緒的?

  • 是多執行緒的。不僅僅是啟動main執行緒,還至少會啟動垃圾回收執行緒的,不然誰幫你回收不用的記憶體~

那麼,既然有兩種方式實現多執行緒,我們使用哪一種???

一般我們使用實現Runnable介面

  • 可以避免java中的單繼承的限制
  • 應該將併發執行任務和執行機制解耦,因此我們選擇實現Runnable介面這種方式!

二、總結

這篇主要是講解了執行緒是什麼,理解執行緒的基礎對我們往後的學習是有幫助的。這裡主要是簡單的入了個門

在閱讀頂部註釋的時候我們發現有”優先順序“、”後臺執行緒“這類的詞,這篇是沒有講解他們是什麼東西的~所以下一篇主要講解的是Thread的API~敬請期待哦~

使用執行緒其實會導致我們資料不安全,甚至程式無法執行的情況的,這些問題都會再後面講解到的~

之前在學習作業系統的時候根據《計算機作業系統-湯小丹》這本書也做了一點點筆記,都是比較淺顯的知識點。或許對大家有幫助~

參考資料:

  • 《Java 核心技術卷一》
  • 《Java併發程式設計實戰》
  • 《計算機作業系統-湯小丹》

如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y

文章的目錄導航

相關文章