最近一直在刷面試題,刷到“如何創建進程”,所以記錄下來
進程一直是面試的熱點問題,創建進程的方式有四種,分別是繼承Thread類創建線程、實現Runnable接口創建線程、使用Callable和Future創建線程、使用線程池例如用Executor框架。
1 繼承Thread類創建線程
通過繼承Thread類來創建並啓動多線程,其代碼如下:
public class MyThread extends Thread{//繼承Thread類
public void run(){
//重寫run方法
}
}
public class Main {
public static void main(String[] args){
new MyThread().start();//創建並啓動線程
}
}
2 實現Runnable接口創建線程
通過實現Runnable接口創建並啓動線程,其代碼如下:
public class MyThread2 implements Runnable {//實現Runnable接口
public void run(){
//重寫run方法
}
}
public class Main {
public static void main(String[] args){
//創建並啓動線程
MyThread2 myThread=new MyThread2();
Thread thread=new Thread(myThread);
thread().start();
//或者 new Thread(new MyThread2()).start();
}
}
3 使用Callable和Future創建線程
和Runnable接口不一樣,Callable接口提供了一個call()方法作爲線程執行體,call()方法比run()方法功能要強大。call()方法可以有返回值;call()方法可以聲明拋出異常。相關代碼如下:
public class ThreadDemo implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
/**
* 求得0到100000的自然數相加,並輸出過程值。
*/
for (int i = 0; i <= 100000; i++) {
System.out.println(i);
sum += i;
}
return sum;
}
}
public class Main {
public static void main(String[] args){
ThreadDemo threadDemo =new ThreadDemo();
// 1.執行Callable方式,需要FutureTask實現類的支持,用於接收運算結果
FutureTask<Integer> task = new FutureTask<Integer>(threadDemo);
new Thread(task).start();
// 2.接收線程運算後的結果
Integer sum;
try {
//等所有線程執行完,獲取值,因此FutureTask 可用於 閉鎖
sum = task.get();
System.out.println("-----------------------------");
System.out.println(sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
4 使用線程池例如用Executor框架
1.5後引入的Executor框架的最大優點是把任務的提交和執行解耦。要執行任務的人只需把Task描述清楚,然後提交即可。
4.1 Executor執行Runnable任務
通過Executors的以上四個靜態工廠方法獲得 ExecutorService實例,而後調用該實例的execute(Runnable command)方法即可。一旦Runnable任務傳遞到execute()方法,該方法便會自動在一個線程上,相關代碼如下:
public class TestRunnable implements Runnable{
@Override
public void run() {
System.out.println("第四種創建線程的方式");
}
}
public class Main {
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++){
// 接收Runnable實例
executorService.execute(new TestRunnable());
System.out.println("************* a" + i + " *************");
}
// 平滑關閉ExecutorService
executorService.shutdown();
}
}
4.2 Executor執行Callable任務
在Java 5之後,任務分兩類:一類是實現了Runnable接口的類,一類是實現了Callable接口的類。兩者都可以被ExecutorService執行,但是Runnable任務沒有返回值,而Callable任務有返回值。並且Callable的call()方法只能通過ExecutorService的submit(Callable task) 方法來執行,並且返回一個 Future,是表示任務等待完成的 Future。相關代碼如下:
public class TaskWithResult implements Callable<String> {
private int id;
/**
* 構造方法
* @param id
*/
public TaskWithResult(int id){
this.id = id;
}
/**
* 任務的具體過程,一旦任務傳給ExecutorService的submit方法,
* 則該方法自動在一個線程上執行
*/
@Override
public String call() throws Exception {
System.out.println("call()方法被自動調用!!! " + Thread.currentThread().getName());
//該返回結果將被Future的get方法得到
return "call()方法被自動調用,任務返回的結果是:" + id + " " + Thread.currentThread().getName();
}
}
public class Main {
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> resultList = new ArrayList<Future<String>>();
// 創建10個任務並執行
for (int i = 0; i < 10; i++){
//使用ExecutorService執行Callable類型的任務,並將結果保存在future變量中
Future<String> future = executorService.submit(new TaskWithResult(i));
//將任務執行結果存儲到List中
resultList.add(future);
}
//遍歷任務的結果
for (Future<String> fs : resultList){
try{
while(!fs.isDone()) {
;//Future返回如果沒有完成,則一直循環等待,直到Future返回完成
}
//打印各個線程(任務)執行的結果
System.out.println(fs.get());
}catch(InterruptedException e){
e.printStackTrace();
}catch(ExecutionException e){
e.printStackTrace();
}finally{
//啓動一次順序關閉,執行以前提交的任務,但不接受新任務
executorService.shutdown();
}
}
}
}
總結
以上方法的代碼都可以運行,並能執行成功,前三種方式理解起來非常簡單,最後一種,要理解就必須看一下Executor框架知識。鏈接如下