1. 程式人生 > >執行緒的基本介紹 一

執行緒的基本介紹 一

1.併發簡史: 執行緒和程序之間的關係以及為什麼要使用執行緒。

        在早期的計算器系統中不存在作業系統,他從頭到尾只能執行一個程式,這個程式能夠訪問計算機中的所有資源,在這種環境中,不僅程式很難編寫,而且極大的造成資源的浪費。作業系統的出現使得可以執行多個程式在上面,這些程式執行在不同的程序中上,作業系統來管理分配給這些程序執行的資源,記憶體、檔案控制代碼、安全證書等。不同的程序之間可以通過一些手段來通訊,包括套接字、共享記憶體以及檔案等。之所以引入作業系統就是為了更合理的使用系統的資源,提高資源的利用率;為了滿足公平性,不同的使用者和不同的程式都可以同時的訪問計算機上的資源,通過時間片的機制類來共享資源,而不僅僅是一個程式從頭執行到尾;便利性,通常來說在計算多個任務時,都是編寫多個程式,程式之間通過通訊機制來相互聯絡這比僅僅編寫一個程式要容易的多。

這些因素同時促進了執行緒的發展,執行緒允許在一個程序中存在多個的程式控制流,多個執行緒共享程序中的資源包括 記憶體控制代碼,檔案控制代碼;每一個執行緒又存在著自己的程式計數器,棧以及區域性變數。執行緒也被稱為輕量級的程序,在大多數的作業系統中都是以執行緒為程式排程的基本單位而不是程序。由於同一個程序上的執行緒都共享著這個程序上的記憶體地址和空間,因此這些執行緒都可以訪問同一個變數並在同一個堆上分配物件。如果沒有明確的協同機制,當一個執行緒在訪問程序上的一個變數時,另一個執行緒可能同時訪問這個變數,這就可能造成無法估量的後果。

 

2.執行緒的建立方式:

① 可以通過繼承Thread類:

package com.wc.study.thread.demo1;

public class CreateThreadByExtends extends Thread{
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName());
	}
	
	public static void main(String[] args) {
		Thread thread1 = new CreateThreadByExtends();
		Thread thread2 = new CreateThreadByExtends();
		thread1.start();
		thread2.start();
	}
}

② 實現Runnable介面:

package com.wc.study.thread.demo1;

public class CreateThreadByRunnable implements Runnable{
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName());
	}
	
	public static void main(String[] args) {
		Thread thread1 = new Thread(new CreateThreadByRunnable());
		Thread thread2 = new Thread(new CreateThreadByRunnable());
		thread1.start();
		thread2.start();
	}
}

③通過Callable介面來建立執行緒:

public class CreateThreadByCallable implements Callable<String>{

	@Override
	public String call() throws Exception {
		return Thread.currentThread().getName();
	}
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		FutureTask<String> futureTask1 = new FutureTask<>(new CreateThreadByCallable());
		FutureTask<String> futureTask2 = new FutureTask<>(new CreateThreadByCallable());
		Thread thread1 = new Thread(futureTask1);
		Thread thread2 = new Thread(futureTask2);
		thread1.start();
		thread2.start();
		System.out.println(futureTask1.get());
		System.out.println(futureTask2.get());
	}
}

④通過執行緒池來建立執行緒:

 1) 通過Executors建立無返回值的執行緒:

package com.wc.study.thread.demo1;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CreateThreadByExecutor {
	public static void main(String[] args) {
		ExecutorService executorService = Executors.newFixedThreadPool(5);
		executorService.execute(()-> System.out.println(Thread.currentThread().getName()));
		executorService.execute(()-> System.out.println(Thread.currentThread().getName()));
		
		executorService.shutdown();
	}
}

2) 通過Executors建立有返回值的執行緒:

package com.wc.study.thread.demo1;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CreateThreadByExecutors2 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService executorService = Executors.newFixedThreadPool(5);
		Future<String> future1 = executorService.submit(() -> {
			return Thread.currentThread().getName();
		});
		Future<String> future2 = executorService.submit(() -> {
			return Thread.currentThread().getName();
		});
		System.out.println(future1.get());
		System.out.println(future2.get());
		
		executorService.shutdown();
	}
}

總結: 

建立執行緒分為兩種: 有返回值和沒有返回值。 沒有返回值推薦使用實現Runnable的方法 重寫其中的 run(),建立有返回值的執行緒實現Callable介面,重寫其中的call() 方法,返回值為FutureTask,此類實現了RunnableFuture介面,是Runnable介面的子類,可以通過get() 方法獲取到想要的返回值.

在使用執行緒池建立執行緒時,使用submit來提交建立的執行緒,建立有返回值的執行緒返回Future,可以通過get() 方法獲取到返回值,建立沒有返回值的執行緒可以通過 executor() 方法和submit(),而建立有返回值的只有通過submit()方法.