java 線程
進程(Process)和線程(Thread)是程序執(zhí)行中的兩個基本單元,在JAVA并發(fā)編程中更關心JAVA線程。
線程(Process)
一個進程是一個自包含的執(zhí)行環(huán)境(可以被看作是程序或應用程序)。一個程序中可以包含多個線程。JAVA運行(JAVA runtime)時作為一個進程運行,可以包含不同的類和程序作為進程。
進程(Thread)
線程可稱為輕量級進程,線程的創(chuàng)建只需要較少的資源并存在于進程中,線程共享進程資源。
Java多線程例子
每個JAVA應用程序至少有一個線程:主線程(Main thread)。 盡管還有諸如:內存管理,系統(tǒng)管理,信號處理等其他線程在后臺運行,但從應用的角度來看:主線程(Main thread)是JAVA應用的第一個線程,我們可以從主線程(Main thread)中創(chuàng)建多個線程。
多線程是指在單個程序中并發(fā)執(zhí)行的兩個或多個線程。單核CPU一次只能執(zhí)行一個線程,而時間片是OS功能,可以共享不同進程和線程之間的處理器時間。
多線程優(yōu)點
- 與進程相比線程是輕量級的,創(chuàng)建線程花費的時間和資源更少。
- 線程共享其父進程數(shù)據(jù)和代碼
- 線程之間的上下文切換通常比進程之間更節(jié)約資源。
- 線程相互通信比進程通信相對容易
java 中創(chuàng)建線程的兩種方式:
- 實現(xiàn)
java.lang.Runnable接口 - 繼承
java.lang.Thread類
Demo 如下:
// 實現(xiàn) runnable 接口
public class HeavyWorkRunnable implements Runnable {
@Override
public void run() {
System.out.println("Doing heavy processing - START "+Thread.currentThread().getName());
try {
Thread.sleep(1000);
//Get database connection, delete unused data from DB
doDBProcessing();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Doing heavy processing - END "+Thread.currentThread().getName());
}
private void doDBProcessing() throws InterruptedException {
Thread.sleep(5000);
}
}
// 繼承 Thread 類
public class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println("MyThread - START "+Thread.currentThread().getName());
try {
Thread.sleep(1000);
//Get database connection, delete unused data from DB
doDBProcessing();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MyThread - END "+Thread.currentThread().getName());
}
private void doDBProcessing() throws InterruptedException {
Thread.sleep(5000);
}
}
// 測試類
public class ThreadRunExample {
public static void main(String[] args){
Thread t1 = new Thread(new HeavyWorkRunnable(), "t1");
Thread t2 = new Thread(new HeavyWorkRunnable(), "t2");
System.out.println("Starting Runnable threads");
t1.start();
t2.start();
System.out.println("Runnable Threads has been started");
Thread t3 = new MyThread("t3");
Thread t4 = new MyThread("t4");
System.out.println("Starting MyThreads");
t3.start();
t4.start();
System.out.println("MyThreads has been started");
}
}
// 輸出:
Starting Runnable threads
Runnable Threads has been started
Doing heavy processing - START t1
Doing heavy processing - START t2
Starting MyThreads
MyThread - START Thread-0
MyThreads has been started
MyThread - START Thread-1
Doing heavy processing - END t2
MyThread - END Thread-1
MyThread - END Thread-0
Doing heavy processing - END t1
Runnable vs Thread
如果你的類有更多的功能,不僅僅是作為線程來運行,你應該實現(xiàn)Runnable接口。如果你的類只作為線程運行,你可以繼承Thread類。
建議采用實現(xiàn)Runnable接口的方式實現(xiàn)多線程,因為JAVA支持實現(xiàn)多個接口,但只能繼承一個父類。
Tip: 注意線程沒有任何返回值,如果你希望線程處理完之后有返回值請查看Callable和Future接口。
Update: 從JAVA8起,Runnable接口成為了一個Functional interface,因此可以使用lambda表達式代替匿名內部類來實現(xiàn)Runnable接口,更多相關的知識請閱讀Java 8 Functional Interfaces
線程生命周期
使用多線程編程時,了解線程生命周期非常重要。JAVA線程的生命周期如下:
下圖展示了JAVA中線程的生命周期,我們可以在代碼中中創(chuàng)建一個新的線程并啟動它,但是該線程的狀態(tài)遷移比如:從Runnable到Running再到Blocked并不是由JAVA程序控制的而是由線程調度程序的OS控制的。

New:當我們用new關鍵字創(chuàng)建一個新的線程對象時,線程的狀態(tài)是New Thread,此時,線程是不存在,new 出來的這個對象它只是Java程序內部的一個變量。
Runnable:當我們在線程對象上執(zhí)行start()方法后,這個線程對象的狀態(tài)遷移為Runnable,對這個線程的控制將被轉交給線程調度程序(Thread scheduler),是立即執(zhí)行這個線程還是將這個線程保持為Runnable狀態(tài)并放在runnable線程池中,完全依賴OS的thread scheduler實現(xiàn)。