1. 程式人生 > >Java執行緒狀態、執行緒停止、執行緒阻塞

Java執行緒狀態、執行緒停止、執行緒阻塞

執行緒狀態(五種狀態)

Java 執行緒的生命週期包括建立,就緒,執行,阻塞,死亡5 個狀態。一個 Java 執行緒總是處於這 5 個生命週期狀態之一,並在一定條件下可以在不同狀態之間進行轉換 。

建立狀態 (New Thread)
在 Java 語言中使用 new操作符建立一個執行緒後,該執行緒僅僅是一個空物件,它具備了執行緒的一些特徵,但此時系統沒有為其分配資源,這時的執行緒處於建立狀態。

就緒狀態 (Runnable)
使用 start()方法啟動一個執行緒後,系統為該執行緒分配了除 CPU 外的所需資源,使該執行緒處於就緒狀態。此外,如果某個執行緒執行了 yield() 方法,那麼該執行緒會被暫時剝奪 CPU 資源,重新進入就緒狀態。

執行狀態 (Running)
Java執行系統通過排程選中一個處於就緒狀態的執行緒,使其佔有 CPU 並轉為執行狀態。此時,系統真正執行執行緒的 run() 方法。

阻塞狀態 (Blocked)
一個正在執行的執行緒因某些原因不能繼續執行時,它就進入阻塞狀態。
這些原因包括:當執行了某個執行緒物件的suspend()、sleep()等阻塞型別的方法時,該執行緒物件會被置入一個阻塞集(Blocked Pool)內,等待被喚醒(執行 resume()方法)或是因為超時而時自動甦醒;
當多個執行緒試圖進入某個同步區域(synchronized)時,沒能進入該同步區域的執行緒會被置入鎖定集(Lock Pool),直到獲得該同步區域的鎖,進入就緒狀態;
當執行緒執行了某個物件的 wait()

方法時,執行緒會被置入該物件的等待集(Wait Pool)中,直到執行了該物件的 notify()方法,wait()/notify()方法的執行要求執行緒首先獲取到該物件的鎖。

死亡狀態 (Dead)
執行緒在 run() 方法執行結束後進入死亡狀態。此外,如果執行緒執行了 interrupt()stop() 方法,那麼它也會以異常退出的方式進入死亡狀態。

停止執行緒(兩種方式)

1、自然終止:執行緒體正常執行完畢
2、外部干涉

1)執行緒類中 定義執行緒體使用的標識。
2)執行緒體使用該標識。
3)提供對外的方法,改變該標識。
4) 外部根據條件呼叫該方法即可

注意:避免使用Thread類自己提供的stop()(具有不安全性)、suspend()(具有固有的死鎖現象)、resume()

等方法

package Threadstate;

/**
 * 停止執行緒
 * @author liguodong
 */
public class Demo01 {
    public static void main(String[] args) {
        Study s = new Study();
        new Thread(s).start();//啟動
        //外部干涉
        for(int i=0;i<100;i++)
        {
            if(50==i)//外部干涉(並不是非常準確,還要看CPU)
            {
                s.stop();
            }
            System.out.println("main....-->"+i);
        }
    }   
}

class Study implements Runnable
{
    //1、執行緒類中,定義執行緒體使用的標識
    private boolean flag = true;    
    @Override
    public void run() {
        //2、執行緒體使用該標識
        while(flag)
        {
            System.out.println("Study thread....");
        }       
    }
    //3、對外提供方法改變標識
    public void stop()
    {
        this.flag = false;
    }
}

執行緒阻塞

1、join:合併執行緒
2、yield:暫停自己的執行緒 static方法
3、sleep:指定的毫秒數內讓當前正在執行的執行緒休眠(暫停執行),不會釋放鎖。
(1)與時間相關,如倒計時
(2)模擬網路延時

package Threadstate;

/**
 * 執行緒阻塞: join合併執行緒   
 */
public class Demo02 extends Thread{

    @Override
    public void run() {
        for(int i=0;i<100;i++)
        {
                System.out.println("join..."+i);            
        }   
    }   
    public static void main(String[] args) throws InterruptedException {

        Demo02 demo = new Demo02();
        Thread t = new Thread(demo);//新生
        t.start();//就緒
        //cpu排程執行       
        for(int i=0;i<100;i++)
        {
            if(50==i)
            {
                t.join();//main阻塞
            }
            System.out.println("main..."+i);                
        }
    }
}
package Threadstate;
/**
 * yield:暫停自己的執行緒   static方法
 * @author liguodong
 */
public class Demo03 extends Thread{
    public static void main(String[] args) {
        Demo03 demo = new Demo03(); 
        Thread t  = new Thread(demo);//新生
        t.start();//就緒
        //cpu排程執行       
        for(int i=0; i<1000; i++)
        {
            if(i%20==0)
            {
                //在main執行緒中,暫停本執行緒main   
                //本方法寫在那個執行緒體裡面就停止那個執行緒,如果在run裡面暫停 Demo03。
                Thread.yield();//靜態方法(並沒有嚴格意義上的暫停,可能CPU又排程到它)
            }
            System.out.println("main..."+i);
        }

    }   
    @Override
    public void run() {
        for(int i=0; i<1000; i++)
        {   
            System.out.println("yield..."+i);
        }
    }
}
package Threadstate;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * sleep:指定的毫秒數內讓當前正在執行的執行緒**休眠**(暫停執行),不會釋放鎖。
 * 倒計時
 * 1、倒數十個數,1秒內列印一個
 * 2、倒計時
 */
public class Demo04 {
    public static void main(String[] args) throws InterruptedException
    {       
        //test01();
        test02();   
    }   
    //倒數十個數,1秒內列印一個
    public static void test01() throws InterruptedException
    {
        int num = 10;
        while(true)
        {
            System.out.println(num--);
            Thread.sleep(1000);//暫停
            if(num<=0)
            {
                break;
            }
        }
    }

    //倒計時
    public static void test02() throws InterruptedException
    {
        //new Date()當前時間   System.currentTimeMillis()也表示當前時間
        Date endTime = new Date(System.currentTimeMillis()+10*1000);//當前時間往後10秒
        long end = endTime.getTime();//獲取結束時間的長整型
        while(true)
        {
            //輸出
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(endTime));
            //構建下一秒的時間
            endTime = new Date(endTime.getTime()-1000);//減一秒  endTime依次遞減
            //等待1秒
            Thread.sleep(1000);//暫停
            //10秒以內繼續   否則退出 end-10000當前時間  
            if(end-10000>endTime.getTime())
            {
                break;
            }
        }   
    }       
}
package Threadstate;

/**
 * sleep模擬網路延時  執行緒不安全的類   結果可能不準確
 */
public class Demo05 {
    public static void main(String[] args) {
        //真實角色
        Web12306 web = new Web12306();
        //代理
        Thread t1 = new Thread(web,"德瑪西亞");
        Thread t2 = new Thread(web,"卡特琳娜");
        Thread t3 = new Thread(web,"德邦總管");
        //啟動執行緒
        t1.start();
        t2.start();
        t3.start();
    }
}

class Web12306 implements Runnable{
    private int num = 50;
    @Override
    public void run() {
        while(true)
        {
            if(num<=0)
            {
                break;//跳出迴圈
            }
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"搶到了倒數第"+num--+"張");            
        }
    }
}