前言:對于java多線程的資料數(shù)不勝數(shù),我們這里只是在學(xué)習(xí)后簡單地總結(jié)一下并給出一些小例子,本文適合java初學(xué)者。不過在開始之前,我們還是要弄明白一個問題——線程和進程有什么區(qū)別?其實一個進程是一個獨立的運行環(huán)境,它可以被看作一個程序或者一個應(yīng)用,而線程是在進程中執(zhí)行的一個任務(wù),線程是進程的子集,一個進程可以有很多線程,每條線程并行執(zhí)行不同的任務(wù)。不同的進程使用不同的內(nèi)存空間,而所有的線程共享一片相同的內(nèi)存空間。別把它和棧內(nèi)存搞混,每個線程都擁有單獨的棧內(nèi)存用來存儲本地數(shù)據(jù)。
1.創(chuàng)建線程的方法
創(chuàng)建線程方法一:繼承Thread類,使用子類創(chuàng)建
編寫繼承Thread子類MyThread
//MyThread.java
public class MyThread extends Thread{
? ?private String name;
? ?public MyThread(String name){
? ? ? this.name= name;
? ?}
? ?//繼承Thread類必須重寫run()方法
? ?@Override
? ?public void run() {
? ? ? System.out.println("name:" + name + "子線程ID:"
? ? ? + Thread.currentThread().getId());
? ?}
}
在main方法里面編寫代碼:
System.out.println("主線程ID:"+ Thread.currentThread().getId());
//創(chuàng)建多個子線程
for(int i = 0; i < 5; i++){
? ?String threadName = "Thread" + (i + 1);
? ?MyThread thread = new MyThread(threadName);
? ?thread.start();
}
//注:直接調(diào)用Thread的run方法,并不會在新的線程上執(zhí)行,而是跟普通方法調(diào)用一樣,在當(dāng)前線程上執(zhí)行
MyThread threadSpec = new MyThread("ThreadSpec"); ? //特例
threadSpec.run();

說明:啟動線程是通過start()方法,而不是調(diào)用run()方法,在線程獲取cpu執(zhí)行時間的時候會自動調(diào)用run()方法。
創(chuàng)建線程方法二:實現(xiàn)Runnable接口,在Runnable上定義任務(wù),然后將Runnable交由Thread執(zhí)行
編寫實現(xiàn)Runnable的實現(xiàn)類MyRunnable
//MyRunnable.java
public class MyRunnable implements Runnable {
? ?public MyRunnable(){}
? ?//實現(xiàn)Runnable接口必須重寫其run方法
? ?@Override
? ?public void run() {
? ? ? System.out.println("子線程ID:"+ Thread.currentThread().getId());
? ?}
}
在main方法里面編寫代碼:
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();

說明:和方法一對比,方法二可能有些啰嗦,但是Java只允許單繼承,如果實際情況中類需要繼承其他類,則只能選擇方法二來實現(xiàn)多線程。
2.使用ExecutorService、Callable、Future實現(xiàn)有返回結(jié)果的多線程
先編寫實現(xiàn)Callable的實現(xiàn)類MyCallable
//MyCallable.java
public class MyCallable implements Callable {
? ?private String taskIndex;
? ?MyCallable(String taskIndex){
? ? ? this.taskIndex = taskIndex;
}
? ?@Override
? ?public Object call() throws Exception {
? ? ? System.out.println(taskIndex + "號任務(wù)啟動");
? ? ? Date startDate = new Date();
? ? ? Thread.sleep(1000);
? ? ? Date endDate = new Date();
? ? ? long time = endDate.getTime() - startDate.getTime();
? ? ? System.out.println(taskIndex + "號任務(wù)終止");
? ? ? return taskIndex + "號任務(wù)返回運行結(jié)果,當(dāng)前任務(wù)執(zhí)行【" + time +"毫秒】";
? ?}
}
在main方法里面編寫代碼:
//使用ExecutorService、Callable、Future實現(xiàn)有返回結(jié)果的多線程
System.out.println("------程序開始運行-----");
Date startDate = new Date();
int taskSize = 5;
//創(chuàng)建一個線程池
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
//創(chuàng)建多個有返回值的任務(wù)
List list =new ArrayList<>();
for(int i =0;i < taskSize;i++){
? ?Callable c = new MyCallable(i +"");
? ?//執(zhí)行任務(wù)并獲取Future對象
? ?Future f = pool.submit(c);
? ?list.add(f);
}
//關(guān)閉線程池
pool.shutdown();
//獲取所有并發(fā)任務(wù)的運行結(jié)果
for(Future f : list){
? ?//從Future對象上獲取任務(wù)的返回值
? ?System.out.println(f.get().toString());
}
Date endDate =new Date();
System.out.println("------程序結(jié)束運行-----,程序運行了【"+ (endDate.getTime() - startDate.getTime()) +"毫秒】");

說明:ExecutorService、Callable、Future這個對象實際上都是屬于Executor框架中的功能類。想要詳細了解Executor框架的可以訪問Java程序員必備知識-多線程框架Executor詳解。實現(xiàn)Callable接口,執(zhí)行Callable任務(wù)后,可以獲取一個Future的對象,在該對象上調(diào)用get就可以獲取到Callable任務(wù)返回的Object了。
注:以上內(nèi)容是學(xué)習(xí)java 多線程后的一個簡單的總結(jié),如果有錯誤,請各位指出,也歡迎大家前來拍磚,灰常感謝!