Java入門教程十三(多線程)

Java入門教程十三(多線程)

線程的概念

單純種以一個任務完成以後再進行下一個任務的模式進行,這樣下一個任務的開始必須等待前一個任務的結束,只有一個任務完成後才能進行下一個任務。Java 語言提供了併發機制,允許開發人員在程序中執行多個線程,每個線程完成一個功能,並與其他線程併發執行。這種機制被稱為多線程。操作系統以進程為單位,我們下Windows

Java入門教程十三(多線程)

系統可以分配給每個進程一段有限的執行 CPU 的時間(也稱為 CPU 時間片),CPU 在這段時間中執行某個進程,然後下一個時間段又跳到另一個進程中去執行。由於 CPU 切換的速度非常快,給使用者的感受就是這些任務似乎在同時運行,所以使用多線程技術後,可以在同一時間內運行更多不同種類的任務。

單任務的特點就是排隊執行,也就是同步,就像在 cmd 中輸入一條命令後,必須等待這條命令執行完才可以執行下一條命令一樣。

Java入門教程十三(多線程)

CPU 完全可以在任務 1 和任務 2 之間來回切換,使任務 2 不必等到 5 秒再運行,系統的運行效率大大得到提升。這就是要使用多線程技術,線程可以理解成是在進程中獨立運行的子任務。

實現方式

實現多線程編程的方式主要有兩種:一種是繼承 Thread 類,另一種是實現 Runnable 接口

Thread類

public Thread(String threadName)
public Thread()
public class NewThread extends Thread{
	 @Override
 public void run(){
 //線程的執行代碼
 }
}
//使用
new NewThread().start();

線程實現的業務代碼需要放到 run() 方法中。當一個類繼承 Thread 類後,就可以在該類中覆蓋 run() 方法,將實現線程功能的代碼寫入 run() 方法中,然後同時調用 Thread 類的 start() 方法執行線程,也就是調用 run() 方法

Runnable接口

如果要創建的線程類已經有一個父類,這時就不能再繼承 Thread 類,因為 Java 不支持多繼承,所以需要實現 Runnable 接口來應對這樣的情況

public Thread(Runnable r);
public Thread(Runnable r,String name);
public class MyRunnable implements Runnable{
 @Override 
 public void run(){ 
 //線程的執行代碼
 }
}
//使用
Runnable runnable=new MyRunnable();
Thread thread=new Thread(runnable);
thread.start();
 

線程的生命週期

線程也具有生命週期,主要包括 7 種狀態,分別是出生狀態、就緒狀態、運行狀態、等待狀態、休眠狀態、阻塞狀態和死亡狀態

Java入門教程十三(多線程)

出生狀態:用戶在創建線程時所處的狀態,在用戶使用該線程實例調用 start() 方法之前,線程都處於出生狀態。

就緒狀態:也稱可執行狀態,當用戶調用 start() 方法之後,線程處於就緒狀態。

運行狀態:當線程得到系統資源後進入運行狀態。

等待狀態:當處於運行狀態下的線程調用 Thread 類的 wait() 方法時,該線程就會進入等待狀態。進入等待狀態的線程必

須調用 Thread 類的 notify() 方法才能被喚醒。notifyAll() 方法是將所有處於等待狀態下的線程喚醒。

休眠狀態:當線程調用 Thread 類中的 sleep() 方法時,則會進入休眠狀態。

阻塞狀態:如果一個線程在運行狀態下發出輸入/輸出請求,該線程將進入阻塞狀態,在其等待輸入/輸出結束時,線程進入就緒狀態。對阻塞的線程來說,即使系統資源關閉,線程依然不能回到運行狀態。

死亡狀態:當線程的 run() 方法執行完畢,線程進入死亡狀態。

同步機制 synchronized

為了處理這種共享資源競爭,可以使用同步機制。所謂同步機制,指的是兩個線程同時作用在一個對象上,應該保持對象數據的統一性和整體性。Java 提供 synchronized 關鍵字,為防止資源衝突提供了內置支持。

同步方法

class className{
 public synchronized type methodName(){
 //代碼
 }
}

同步塊

synchronized(obj){
 //代碼
}
public class test{
	Object obj=new Object();
	public void method(){
 	synchronized(obj){
 	//代碼
 	}
	}
}

同步的多線程與單線程有本質的區別,當處理一段非常複雜的業務時,使用了多線程處理,只有被synchronized的代碼塊才會被進行順序執行,其他的業務代碼都是在不同的線程裡各自執行。

curentThread()

返回代碼段正在被哪個線程調用的線程相關信息

public static void main(String[] args)
{
 //調用currentThread()方法輸出當前線程名稱
 System.out.println(Thread.currentThread().getName());
}
public class MyThread extends Thread{
	@Override 
 public void run(){
 		System.out.println(Thread.currentThread().getName()); 
 }
}
MyThread myThread=new MyThread();
Thread t = new Thread(myThread);
t.setName("myThread");
t.start();//輸出myThread;

isAlive()

isAlive() 方法的作用是判斷當前的線程是否處於活動狀態。什麼是活動狀態呢?活動狀態就是線程已經啟動且尚未終止。線程處於正在運行或準備開始運行的狀態,就認為線程是“存活”的

public class MyThread extends Thread
{
 @Override 
 public void run()
 { 
 System.out.println("run="+this.isAlive()); 
 }
}
public static void main(String[] args)
{
 MyThread mythread=new MyThread(); 
 System.out.println("begin="+mythread.isAlive()); //輸出線程狀態
 mythread.start(); //啟動線程
 System.out.println("end="+mythread.isAlive()); //輸出線程狀態
}
//輸出
begin==false
end==true或false//這裡要注意,由於另啟一個線程,去執行代碼,end有可能在線程啟動前執行(此情況end為false),也有可能在線程啟動後執行(此情況end為ture)
run=true
 

sleep()

sleep() 方法的作用是在指定的毫秒數內讓當前“正在執行的線程”休眠(暫停執行)

public class MyThread extends Thread
{
 @Override 
 public void run()
 { 
 System.out.println("開始"); 
 Thread.sleep(2000); //延時2秒
 System.out.println("結束"); 
 }
}

getId()

getId() 取得正在運行線程的唯一標識

Thread thread=Thread.currentThread();
System.out.println(thread.getId());

線程暫停

暫停線程意味著此線程還可以恢復運行。使用 suspend() 方法暫停線程,使用 resume() 方法恢復線程的執行

public class MyThread extends Thread
{
 private long i=0;
 public long getI()
 {
 return i;
 }
 public void setI(long i)
 {
 this.i=i;
 }
 @Override
 public void run()
 {
 while(true)
 {
 i++;
 }
 }
}
public static void main(String[] args){
 MyThread thread=new MyThread();
 thread.start();
 System.out.println("線程開始");
 System.out.println(System.currentTimeMillis()+" i= "+thread.getI());//輸出i的值
 thread.suspend();//暫停
 System.out.println("線程暫停5秒");
 Thread.sleep(5000);
 thread.resume();//開始
 System.out.println(System.currentTimeMillis()+" i= "+thread.getI());//繼續暫停後i的值
} 

注意:在使用 suspend() 方法與 resume() 方法時,如果使用不當極易造成公共的同步對象被獨佔,從而使得其他線程無法訪問公共同步對象。使用時要格外注意。

線程停止

停止一個線程意味著在線程處理完任務之前停掉正在做的操作,也就是放棄當前的操作。有三種方法可以停止線程

使用退出標識,使線程正常退出,也就是當 run() 方法完成後線程終止。
使用 stop() 方法強行終止線程,但是不推薦使用這個方法,因為 stop() 和 suspend() 及 resume() 一樣,都是作廢過期的方法,使用它們可能產生不可預料的結果。
使用 interrupt() 方法中斷線程。

interrupt()

interrupt() 方法的作用是用來停止線程,但 intermpt() 方法的使用效果並不像循環結構中 break 語句那樣,可以馬上停止循環。調用 intermpt() 方法僅僅是在當前線程中打了一個停止的標記,並不是真的停止線程

public class MyThread extends Thread
{
 @Override 
 public void run()
 { 
 for (int i=0;i<10000>

判斷線程是不是停止狀態

this.interrupted():測試當前線程是否已經中斷。
this.islnterrupted():測試線程是否已經中斷。

stop()

調用 stop() 方法可以在任意情況下強制停止一個線程

public class MyThread extends Thread{
 private int i=0;
 @Override 
 public void run(){ 
 			while (true){
 i++;
 System.out.println("i=" + i);
 Thread.sleep(1000);
 	}
 } 
}
MyThread thread=new MyThread();
thread.start();
Thread.sleep(8000);
thread.stop();

線程在啟動後有一個 8000 毫秒的延時,在這段時間內會循環 9 次,之後 stop() 方法被執行從而線程停止。運行後輸出1到9

調用 stop() 方法時會拋出 java.lang.ThreadDeath 異常,但在通常情況下,此異常不需要顯式地捕捉。使用 stop() 釋放鎖將會給數據造成不一致性的結果。如果出現這樣的情況,程序處理的數據就有可能遭到破壞,最終導致程序執行的流程錯誤,一定要特別注意。


分享到:


相關文章: