1.線程是什么?
線程被稱為輕量級進程,是程序執行的最小單位,它是指在程序執行過程中,能夠執行代碼的一個執行單位。每個程序程序都至少有一個線程,也即是程序本身。
2.線程狀態
Java語言定義了5種線程狀態,在任意一個時間點,一個線程只能有且只有其中一個狀態。,這5種狀態如下:
(1)新建(New):創建后尚未啟動的線程處於這種狀態
(2)運行(Runable):Runable包括了操作系統線程狀態的Running和Ready,也就是處於此狀態的線程有可能正在執行,也有可能正在等待着CPU為它分配執行時間。
(3)等待(Wating):處於這種狀態的線程不會被分配CPU執行時間。等待狀態又分為無限期等待和有限期等待,處於無限期等待的線程需要被其他線程顯示地喚醒,沒有設置Timeout參數的Object.wait()、沒有設置Timeout參數的Thread.join()方法都會使線程進入無限期等待狀態;有限期等待狀態無須等待被其他線程顯示地喚醒,在一定時間之后它們會由系統自動喚醒,Thread.sleep()、設置了Timeout參數的Object.wait()、設置了Timeout參數的Thread.join()方法都會使線程進入有限期等待狀態。
(4)阻塞(Blocked):線程被阻塞了,“阻塞狀態”與”等待狀態“的區別是:”阻塞狀態“在等待着獲取到一個排他鎖,這個時間將在另外一個線程放棄這個鎖的時候發生;而”等待狀態“則是在等待一段時間或者喚醒動作的發生。在程序等待進入同步區域的時候,線程將進入這種狀態。
(5)結束(Terminated):已終止線程的線程狀態,線程已經結束執行。
下圖是5種狀態轉換圖:
3.線程同步方法
線程有4中同步方法,分別為wait()、sleep()、notify()和notifyAll()。
wait():使線程處於一種等待狀態,釋放所持有的對象鎖。
sleep():使一個正在運行的線程處於睡眠狀態,是一個靜態方法,調用它時要捕獲InterruptedException異常,不釋放對象鎖。
notify():喚醒一個正在等待狀態的線程。注意調用此方法時,並不能確切知道喚醒的是哪一個等待狀態的線程,是由JVM來決定喚醒哪個線程,不是由線程優先級決定的。
notifyAll():喚醒所有等待狀態的線程,注意並不是給所有喚醒線程一個對象鎖,而是讓它們競爭。
4.創建線程的方式
在JDK1.5之前,創建線程就只有兩種方式,即繼承java.lang.Thread類和實現java.lang.Runnable接口;而在JDK1.5以后,增加了兩個創建線程的方式,即實現java.util.concurrent.Callable接口和線程池。下面是這4種方式創建線程的代碼實現。
4.1繼承Thread類
//繼承Thread類來創建線程 public class ThreadTest { public static void main(String[] args) { //設置線程名字 Thread.currentThread().setName("main thread"); MyThread myThread = new MyThread(); myThread.setName("子線程:"); //開啟線程 myThread.start(); for(int i = 0;i<5;i++){ System.out.println(Thread.currentThread().getName() + i); } } } class MyThread extends Thread{ //重寫run()方法 public void run(){ for(int i = 0;i < 10; i++){ System.out.println(Thread.currentThread().getName() + i); } } }
4.2實現Runnable接口
//實現Runnable接口
public class RunnableTest {
public static void main(String[] args) {
//設置線程名字
Thread.currentThread().setName("main thread:");
Thread thread = new Thread(new MyRunnable());
thread.setName("子線程:");
//開啟線程
thread.start();
for(int i = 0; i <5;i++){
System.out.println(Thread.currentThread().getName() + i);
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
}
4.3實現Callable接口
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; //實現Callable接口 public class CallableTest { public static void main(String[] args) { //執行Callable 方式,需要FutureTask 實現實現,用於接收運算結果 FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyCallable()); new Thread(futureTask).start(); //接收線程運算后的結果 try { Integer sum = futureTask.get(); System.out.println(sum); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } class MyCallable implements Callable<Integer> { @Override public Integer call() throws Exception { int sum = 0; for (int i = 0; i < 100; i++) { sum += i; } return sum; } }
相較於實現Runnable 接口的實現,方法可以有返回值,並且拋出異常。
4.4線程池
線程池提供了一個線程隊列,隊列中保存着所有等待狀態的線程。避免了創建與銷毀額外開銷,提交了響應速度。
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //線程池實現 public class ThreadPoolExecutorTest { public static void main(String[] args) { //創建線程池 ExecutorService executorService = Executors.newFixedThreadPool(10); ThreadPool threadPool = new ThreadPool(); for(int i =0;i<5;i++){ //為線程池分配任務 executorService.submit(threadPool); } //關閉線程池 executorService.shutdown(); } } class ThreadPool implements Runnable { @Override public void run() { for(int i = 0 ;i<10;i++){ System.out.println(Thread.currentThread().getName() + ":" + i); } } }
