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

線程的概念

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

系統能夠分配給每一個進程一段有限的執行 CPU 的時間(也稱爲 CPU 時間片),CPU 在這段時間中執行某個進程,而後下一個時間段又跳到另外一個進程中去執行。因爲 CPU 切換的速度很是快,給使用者的感覺就是這些任務彷佛在同時運行,因此使用多線程技術後,能夠在同一時間內運行更多不一樣種類的任務。編程

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

CPU 徹底能夠在任務 1 和任務 2 之間來回切換,使任務 2 沒必要等到 5 秒再運行,系統的運行效率大大獲得提高。這就是要使用多線程技術,線程能夠理解成是在進程中獨立運行的子任務。併發

實現方式

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

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 接口來應對這樣的狀況this

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 種狀態,分別是出生狀態、就緒狀態、運行狀態、等待狀態、休眠狀態、阻塞狀態和死亡狀態操作系統

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

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

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

等待狀態:當處於運行狀態下的線程調用 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;i++)
        { 
            System.out.println(i+1);
        } 
    } 
}

public static void main(String[] args){ 
    MyThread thread=new MyThread();      //建立MyThread13線程類實例
    thread.start();    //啓動線程
    Thread.sleep(100);    //延時100毫秒
    thread.interrupt();    //中止線程
}

主線程的運行結果以下所示。從中能夠看到,雖然在延時 100 毫秒後調用 intermpt() 方法中止了 thread 線程,可是該線程仍然執行完成輸出 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() 釋放鎖將會給數據形成不一致性的結果。若是出現這樣的狀況,程序處理的數據就有可能遭到破壞,最終致使程序執行的流程錯誤,必定要特別注意。

相關文章
相關標籤/搜索