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()
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--+"張");
}
}
}