1. 程式人生 > 其它 >聊聊執行緒(一)執行緒的基礎

聊聊執行緒(一)執行緒的基礎

技術標籤:執行緒多執行緒java

執行緒基礎

程序和執行緒

  • 程序:正在執行的程式,需要記憶體和CPU資源進行運算執行,
    一個程式包含一個或多個程序
  • 執行緒:是程序的組成單元,一個程序包含一個或多個執行緒,每個執行緒負責單獨執行一個任務
  • 程序和執行緒的區別:
  1. 一個程序包含一個或多個執行緒
  2. 每個程序都有自己獨立的記憶體空間,執行緒沒有自己獨立的記憶體空間,執行緒共享所在程序的記憶體空間
  3. 程序是重量級的單元,需要系統資源比較多,執行緒是輕量級單元,需要資源比較少

多程序和多執行緒

  • 多程序是作業系統可以同時執行多個程序。一個CPU核心一個時間只能執行一個程序,CPU會在多個程序之間進行來回切換,因為速度特別快,使用者感覺不到。
  • 多執行緒是一個程序裡面有多個執行緒,CPU執行程序時會來回切換裡面所有的執行緒,每個執行緒會分配到一定的CPU的執行時間(CPU時間片)

多執行緒的應用場景

  • JAVAEE企業級開發:大量的使用者需要同時訪問網站的伺服器,如:雙十一、秒殺等。如果伺服器只有一個執行緒,多個使用者需要排隊和伺服器通訊,效率非常低;多執行緒就是一個使用者連線伺服器後,伺服器就會開一個新執行緒負責使用者的通訊,使用者之間就不會相互影響。
  • 遊戲開發:同時進行網路通訊、遊戲角色控制、圖形繪製等操作,必須每個用一個執行緒執行。

並行和併發

  • 併發:一個CPU在多個執行緒之間快速切換,達到同時執行多個任務的目的
  • 並行:多個CPU可以同時執行一個程序中的多個執行緒

執行緒的實現

1、 繼承Thread類
  1. 繼承Thread類
  2. 重寫run方法
  3. 建立執行緒物件,呼叫start方法
/**
 * 自定義執行緒類
 * @author xray
 *
 */
public class MyThread extends Thread{

	/**
	 * 執行執行緒任務的方法
	 */
	public void run(){
		//Thread.currentThread()是獲得系統當前執行的執行緒
		System.out.println(Thread.currentThread().getName()+"執行緒執行了!!!");
	}
	
	public static void main(String[] args) {
		//主執行緒中執行
		System.out.println(Thread.currentThread().getName()+"執行緒執行了!!!");
		//建立執行緒物件
		MyThread thread1 = new MyThread();
		MyThread thread2 = new MyThread();
		//啟動執行緒
		thread1.start();
		thread2.start();
	}
}

2、實現Runnable介面
  1. 實現Runnable介面
  2. 實現run方法
  3. 建立自定義執行緒物件,作為引數傳入Thread物件
  4. 呼叫start方法
/**
 * 自定義執行緒類
 * @author xray
 *
 */
public class MyRunnable implements Runnable{

	/**
	 * 實現run方法
	 */
	@Override
	public void run() {
		System.out.println("當前執行的執行緒是:"+Thread.currentThread().getName());
	}
	
	
	public static void main(String[] args) {
		//建立Thread物件,傳入Runnable物件
		Thread thread1 = new Thread(new MyRunnable());
		//呼叫start方法
		thread1.start();
		//使用匿名內部類實現Runnable
		Thread thread2 = new Thread(new Runnable(){
			@Override
			public void run() {
				System.out.println("匿名內部類,當前執行的執行緒是:"+Thread.currentThread().getName());
			}
		});
		thread2.start();
		//使用Lambda實現Runnable
		Thread thread3 = new Thread(()->{
			System.out.println("Lambda,當前執行的執行緒是:"+Thread.currentThread().getName());
			});
		thread3.start();
	}

}
3、實現Callable介面

前面兩種方法都不能返回結果,Callable的方法可以返回值

  1. 實現Callable介面,實現call方法
  2. 建立FutureTask物件,傳入Callable物件
  3. 建立Thread物件,傳入FutureTask物件
  4. 呼叫Thread物件的start方法
  5. 呼叫FutureTask物件的get方法,獲得返回值
/**
 * Callable的實現類
 * @author xray
 *
 */
public class MyCallable implements Callable<Long>{

	@Override
	public Long call() throws Exception {
		System.out.println("執行call的執行緒是:"+Thread.currentThread().getName());
		//模擬執行耗時運算
		Long sum = 0L;
		for(int i = 0;i < 100000000L;i++){
			sum += i;
		}
		//返回結果
		return sum;
	}
	
	
	public static void main(String[] args) {
		//建立FutureTask物件,傳入Callable物件
		FutureTask<Long> task = new FutureTask<>(new MyCallable());
		//建立Thread,傳入FutureTask物件
		Thread thread = new Thread(task);
		//啟動執行緒
		thread.start();
		//獲得結果
		try {
//			long result = task.get();
			long result = task.get(5,TimeUnit.SECONDS);
			System.out.println("獲得計算結果:"+result);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} catch (TimeoutException e) {
			e.printStackTrace();
		}
	}
}

執行緒的生命週期

  1. 新建
    執行緒new出來,沒有呼叫start方法,CPU沒有分配時間片
  2. 就緒
    執行緒呼叫了start方法,CPU準備分配時間片,但是沒有真正分配
  3. 執行
    執行緒搶到了CPU,開始執行run方法
  4. 阻塞

    進入阻塞狀態:
    • 呼叫sleep方法
    • 執行緒的鎖呼叫wait方法
    • 呼叫suspend(掛起)方法
    • 流的IO操作

      從阻塞恢復:
    • sleep的時間完畢
    • 鎖呼叫notify或notifyAll方法
    • 呼叫resume(恢復)方法
    • IO操作完畢

阻塞狀態結束後,回到就緒狀態

  1. 死亡,run方法執行完畢後執行緒進入死亡狀態

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-LVvDepw9-1608020657272)(https://note.youdao.com/yws/api/personal/file/94E9AEB01DEC4317B05C579CAA456C24?method=download&shareKey=c26acaf49f7f09777f9e36dc9aab44ff)]