Java 高階 --- 多執行緒快速入門

雲揚四海發表於2019-06-03

這世上有三樣東西是別人搶不走的:一是吃進胃裡的食物,二是藏在心中的夢想,三是讀進大腦的書

多執行緒快速入門

1、執行緒與程式區別

  • 每個正在系統上執行的程式都是一個程式。每個程式包含一到多個執行緒。執行緒是一組指令的集合,或者是程式的特殊段,它可以在程式裡獨立執行。 所以執行緒基本上是輕量級的程式,它負責在單個程式裡執行多工。通常由作業系統負責多個執行緒的排程和執行。

  • 使用執行緒可以把佔據時間長的程式中的任務放到後臺去處理,程式的執行速度可能加快,在一些等待的任務實現上如使用者輸入、檔案讀寫和網路收發資料等,執行緒就比較有用了。在這種情況下可以釋放一些珍貴的資源如記憶體佔用等等。

  • 如果有大量的執行緒,會影響效能,因為作業系統需要在它們之間切換,更多的執行緒需要更多的記憶體空間,執行緒的中止需要考慮其對程式執行的影響。通常塊模型資料是在多個執行緒間共享的,需要防止執行緒死鎖情況的發生。

  • 總結:程式是所有執行緒的集合,每一個執行緒是程式中的一條執行路徑。

2、為什麼要使用多執行緒?

  • (1)、使用多執行緒可以減少程式的響應時間。單執行緒如果遇到等待或阻塞,將會導致程式不響應滑鼠鍵盤等操作,使用多執行緒可以解決此問題,增強程式的互動性。

  • (2)、與程式相比,執行緒的建立和切換開銷更小,因為執行緒共享程式碼段、資料段等記憶體空間。

  • (3)、多核CPU,多核計算機本身就具有執行多執行緒的能力,如果使用單個執行緒,將無法重複利用計算資源,造成資源的巨大浪費。

  • (4)、多執行緒可以簡化程式的結構,使程式便於維護,一個非常複雜的程式可以分為多個執行緒執行。

3、多執行緒應用場景?

  • 答:主要能體現到多執行緒提高程式效率。
  • 舉例: 迅雷多執行緒下載、資料庫連線池、分批傳送簡訊等。

4、多執行緒建立方式

第一種、 繼承Thread類 重寫run方法

class CreateThread extends Thread {
	// run方法中編寫 多執行緒需要執行的程式碼
	publicvoid run() {
		for (inti = 0; i< 10; i++) {
			System.out.println("i:" + i);
		}
	}
}
publicclass ThreadDemo {

	publicstaticvoid main(String[] args) {
		System.out.println("-----多執行緒建立開始-----");
		// 1.建立一個執行緒
		CreateThread createThread = new CreateThread();
		// 2.開始執行執行緒 注意 開啟執行緒不是呼叫run方法,而是start方法
		System.out.println("-----多執行緒建立啟動-----");
		createThread.start();
		System.out.println("-----多執行緒建立結束-----");
	}

}
複製程式碼

Java 高階 --- 多執行緒快速入門

  • 呼叫start方法後,程式碼並沒有從上往下執行,而是有一條新的執行分支

  • 注意:畫圖演示多執行緒不同執行路徑。

Java 高階 --- 多執行緒快速入門

第二種、實現Runnable介面,重寫run方法

class CreateRunnable implements Runnable {

	@Override
	publicvoid run() {
		for (inti = 0; i< 10; i++) {
			System.out.println("i:" + i);
		}
	}

}
publicclass ThreadDemo2 {
	publicstaticvoid main(String[] args) {
		System.out.println("-----多執行緒建立開始-----");
		// 1.建立一個執行緒
		CreateRunnable createThread = new CreateRunnable();
		// 2.開始執行執行緒 注意 開啟執行緒不是呼叫run方法,而是start方法
		System.out.println("-----多執行緒建立啟動-----");
		Thread thread = new Thread(createThread);
		thread.start();
		System.out.println("-----多執行緒建立結束-----");
	}
}
複製程式碼

第三種、使用匿名內部類方式

 System.out.println("-----多執行緒建立開始-----");
		 Thread thread = new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i< 10; i++) {
					System.out.println("i:" + i);
				}
			}
		});
		 thread.start();
		 System.out.println("-----多執行緒建立結束-----");
複製程式碼

5、使用繼承Thread類還是使用實現Runnable介面好?

  • 使用實現實現Runnable介面好,原因實現了介面還可以繼續繼承,繼承了類不能再繼承。

6、啟動執行緒是使用呼叫start方法還是run方法?

  • 開始執行執行緒 注意 開啟執行緒不是呼叫run方法,而是start方法呼叫run知識使用例項呼叫方法。

7、獲取執行緒物件以及名稱

常用執行緒api方法
start()
currentThread()
getID()
getName()
sleep(long mill)
Stop()
常用執行緒建構函式
Thread()
Thread(String name)
Thread(Runable r)
Thread(Runable r, String name)

8、守護執行緒

  • Java中有兩種執行緒,一種是使用者執行緒,另一種是守護執行緒。
  • 使用者執行緒是指使用者自定義建立的執行緒,主執行緒停止,使用者執行緒不會停止
  • 守護執行緒當程式不存在或主執行緒停止,守護執行緒也會被停止。
  • 使用setDaemon(true)方法設定為守護執行緒
public class DaemonThread {

	public static void main(String[] args) {
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					try {
						Thread.sleep(100);
					} catch (Exception e) {
						// TODO: handle exception
					}
					System.out.println("我是子執行緒...");
				}
			}
		});
		thread.setDaemon(true);
		thread.start();
		for (int i = 0; i < 10; i++) {
			try {
				Thread.sleep(100);
			} catch (Exception e) {

			}
			System.out.println("我是主執行緒");
		}
		System.out.println("主執行緒執行完畢!");
	}

}
複製程式碼

9、多執行緒執行狀態

Java 高階 --- 多執行緒快速入門

  • 執行緒從建立、執行到結束總是處於下面五個狀態之一:新建狀態就緒狀態執行狀態阻塞狀態死亡狀態

新建狀態

  • 當用new操作符建立一個執行緒時, 例如new Thread(r),執行緒還沒有開始執行,此時執行緒處在新建狀態。 當一個執行緒處於新生狀態時,程式還沒有開始執行執行緒中的程式碼

就緒狀態

  • 一個新建立的執行緒並不自動開始執行,要執行執行緒,必須呼叫執行緒的start()方法。當執行緒物件呼叫start()方法即啟動了執行緒,start()方法建立執行緒執行的系統資源,並排程執行緒執行run()方法。當start()方法返回後,執行緒就處於就緒狀態。
  • 處於就緒狀態的執行緒並不一定立即執行run()方法,執行緒還必須同其他執行緒競爭CPU時間,只有獲得CPU時間才可以執行執行緒。因為在單CPU的計算機系統中,不可能同時執行多個執行緒,一個時刻僅有一個執行緒處於執行狀態。因此此時可能有多個執行緒處於就緒狀態。對多個處於就緒狀態的執行緒是由Java執行時系統的執行緒排程程式(thread scheduler)來排程的。

執行狀態

  • 當執行緒獲得CPU時間後,它才進入執行狀態,真正開始執行run()方法. 阻塞狀態執行緒執行過程中,可能由於各種原因進入阻塞狀態:

      1>執行緒通過呼叫sleep方法進入睡眠狀態;
      2>執行緒呼叫一個在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會返回到它的呼叫者;
    複製程式碼

3>執行緒試圖得到一個鎖,而該鎖正被其他執行緒持有;    4>執行緒在等待某個觸發條件;

死亡狀態

  • 有兩個原因會導致執行緒死亡:  - - 1) run方法正常退出而自然死亡,  - - 2) 一個未捕獲的異常終止了run方法而使執行緒猝死。 -  為了確定執行緒在當前是否存活著(就是要麼是可執行的,要麼是被阻塞了),需要使用isAlive方法。如果是可執行或被阻塞,這個方法返回true; 如果執行緒仍舊是new狀態且不是可執行的, 或者執行緒死亡了,則返回false.

join()方法作用

  • 當在主執行緒當中執行到t1.join()方法時,就認為主執行緒應該把執行權讓給t1

建立一個執行緒,子執行緒執行完畢後,主執行緒才能執行。

Thread t1 = new Thread(new Runnable() {

			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					try {
						Thread.sleep(10);
					} catch (Exception e) {

					}
					System.out.println(Thread.currentThread().getName() + "i:" + i);
				}
			}
		});
		t1.start();
		// 當在主執行緒當中執行到t1.join()方法時,就認為主執行緒應該把執行權讓給t1
		t1.join();
		for (int i = 0; i < 10; i++) {
			try {
				Thread.sleep(10);
			} catch (Exception e) {

			}
			System.out.println("main" + "i:" + i);
		}
        
複製程式碼
  • 優先順序
  • 現代作業系統基本採用時分的形式排程執行的執行緒,執行緒分配得到的時間片的多少決定了執行緒使用處理器資源的多少,也對應了執行緒優先順序這個概念。在JAVA執行緒中,通過一個int priority來控制優先順序,範圍為1-10,其中10最高,預設值為5。下面是原始碼(基於1.8)中關於priority的一些量和方法。
class PrioritytThread implements Runnable {

	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().toString() + "---i:" + i);
		}
	}
}
public class ThreadDemo4 {

	public static void main(String[] args) {
		PrioritytThread prioritytThread = new PrioritytThread();
		Thread t1 = new Thread(prioritytThread);
		Thread t2 = new Thread(prioritytThread);
		t1.start();
		// 注意設定了優先順序, 不代表每次都一定會被執行。 只是CPU排程會有限分配
		t1.setPriority(10);
		t2.start();
		
	}

}
複製程式碼

Yield方法

Thread.yield()方法的作用:暫停當前正在執行的執行緒,並執行其他執行緒。(可能沒有效果) yield()讓當前正在執行的執行緒回到可執行狀態,以允許具有相同優先順序的其他執行緒獲得執行的機會。因此,使用yield()的目的是讓具有相同優先順序的執行緒之間能夠適當的輪換執行。但是,實際中無法保證yield()達到讓步的目的,因為,讓步的執行緒可能被執行緒排程程式再次選中。 結論:大多數情況下,yield()將導致執行緒從執行狀態轉到可執行狀態,但有可能沒有效果。

總結

  • 1.程式與執行緒的區別?
    • 答:程式是所有執行緒的集合,每一個執行緒是程式中的一條執行路徑,執行緒只是一條執行路徑。
  • 2.為什麼要用多執行緒?
    • 答:提高程式效率
  • 3.多執行緒建立方式?
      • 答:繼承Thread或Runnable 介面。
  • 4.是繼承Thread類好還是實現Runnable介面好?
    • 答:Runnable介面好,因為實現了介面還可以繼續繼承。繼承Thread類不能再繼承。
  • 5.你在哪裡用到了多執行緒?
    • 答:主要能體現到多執行緒提高程式效率。
    • 舉例:分批傳送簡訊、迅雷多執行緒下載等。

總結不易,給個關注吧 github.com/yunlongn

相關文章