中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java之多線程方法狀態和創建方法的示例分析

發布時間:2021-09-05 16:17:57 來源:億速云 閱讀:138 作者:小新 欄目:開發技術

這篇文章主要為大家展示了“Java之多線程方法狀態和創建方法的示例分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Java之多線程方法狀態和創建方法的示例分析”這篇文章吧。

    Java之線程的五大狀態及其常用方法(六個狀態還有timed_wating超時等待)

    1.線程的五大狀態及其轉換

    線程的五大狀態分別為:創建狀態(New)、就緒狀態(Runnable)、運行狀態(Running)、阻塞狀態(Blocked)、死亡狀態(Dead)。

    下面畫出線程五大狀態之間的關系圖:

    Java之多線程方法狀態和創建方法的示例分析

    (1)新建狀態:即單純地創建一個線程,創建線程有三種方式,在我的博客:線程的創建,可以自行查看!

    (2)就緒狀態:在創建了線程之后,調用Thread類的start()方法來啟動一個線程,即表示線程進入就緒狀態!

    (3)運行狀態:當線程獲得CPU時間,線程才從就緒狀態進入到運行狀態!

    (4)阻塞狀態:線程進入運行狀態后,可能由于多種原因讓線程進入阻塞狀態,如:調用sleep()方法讓線程睡眠,調用wait()方法讓線程等待,調用join()方法、suspend()方法(它現已被棄用!)以及阻塞式IO方法。

    (5)死亡狀態:run()方法的正常退出就讓線程進入到死亡狀態,還有當一個異常未被捕獲而終止了run()方法的執行也將進入到死亡狀態!

    2.設置或獲取多線程的線程名稱的方法

    由于在一個進程中可能有多個線程,而多線程的運行狀態又是不確定的,即不知道在多線程中當前執行的線程是哪個線程,所以在多線程操作中需要有一個明確的標識符標識出當前線程對象的信息,這個信息往往通過線程的名稱來描述。在Thread類中提供了一些設置或獲取線程名稱的方法:

    (1)創建線程時設置線程名稱:

    public Thread(Runnable target,String name)

    (2)設置線程名稱的普通方法:

    public final synchronized void setName(String name)

    (3)取得線程名稱的普通方法:

    public final String getName()

    演示:

    class MyThread implements Runnable{
    	@Override
    	public void run() {
    		for(int i=0;i<5;i++)
    		{
    			//currentThread()方法用于取得當前正在JVM中運行的線程
    			//使用getName()方法,用于獲取線程的名稱
    			System.out.println("當前線程:"+Thread.currentThread().getName()+"-----i="+i);
    		}
    	}
    }
    public class Test1 {
    	public static void main(String[] args){
    		//創建線程對象thread1且沒有設置線程名稱
    		MyThread myThread1=new MyThread();
    		Thread thread1=new Thread(myThread1);
    		thread1.start();
    		//創建線程對象thread2且使用setName設置線程名稱
    		MyThread myThread2=new MyThread();
    		Thread thread2=new Thread(myThread2);
    		thread2.setName("線程2");
    		thread2.start();
    		//創建線程對象thread3并在創建線程時設置線程名稱
    		MyThread myThread3=new MyThread();
    		Thread thread3=new Thread(myThread3,"線程3");
    		thread3.start();
    	}
    }

    輸出:

    當前線程:Thread-0-----i=0
    當前線程:Thread-0-----i=1
    當前線程:Thread-0-----i=2
    當前線程:線程3-----i=0
    當前線程:線程2-----i=0
    當前線程:線程2-----i=1
    當前線程:線程2-----i=2
    當前線程:線程2-----i=3
    當前線程:線程3-----i=1
    當前線程:Thread-0-----i=3
    當前線程:Thread-0-----i=4
    當前線程:線程3-----i=2
    當前線程:線程3-----i=3
    當前線程:線程3-----i=4
    當前線程:線程2-----i=4

    通過上述代碼及其運行結果可知:

    (1)若沒有手動設置線程名稱時,會自動分配一個線程的名稱,如線程對象thread1自動分配線程名稱為Thread-0。

    (2)多線程的運行狀態是不確定的,不知道下一個要執行的是哪個線程,這是因為CPU以不確定方式或以隨機的時間調用線程中的run()方法。

    (3)需要注意的是,由于設置線程名稱是為了區分當前正在執行的線程是哪一個線程,所以在設置線程名稱時應避免重復!

    3.線程休眠------sleep()方法

    線程休眠:指的是讓線程暫緩執行,等到預計時間之后再恢復執行。

    (1)線程休眠會交出CPU,讓CPU去執行其他的任務。

    (2)調用sleep()方法讓線程進入休眠狀態后,sleep()方法并不會釋放鎖,即當前線程持有某個對象鎖時,即使調用sleep()方法其他線程也無法訪問這個對象。

    (3)調用sleep()方法讓線程從運行狀態轉換為阻塞狀態;sleep()方法調用結束后,線程從阻塞狀態轉換為可執行狀態。

    sleep()方法:

    public static native void sleep(long millis) throws InterruptedException;

    從上面方法參數中可以看出sleep()方法的休眠時間是以毫秒作為單位。

    關于sleep()方法的操作如下:

    class MyThread implements Runnable{
    	@Override
    	public void run() {
    		for(int i=0;i<5;i++)
    		{
    			//使用Thread類的sleep()方法,讓線程處于休眠狀態
    			try {
    				Thread.sleep(1000);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			System.out.println("當前線程:"+Thread.currentThread().getName()+"-----i="+i);
    		}
    	}
    }
    public class Test1 {
    	public static void main(String[] args){
    		MyThread myThread=new MyThread();
    		//利用myThread對象分別創建三個線程
    		Thread thread1=new Thread(myThread);
    		thread1.start();
    		Thread thread2=new Thread(myThread);
    		thread2.start();
    		Thread thread3=new Thread(myThread);
    		thread3.start();
    	}
    }

    某次運行結果如下所示:

    當前線程:Thread-2-----i=0
    當前線程:Thread-1-----i=0
    當前線程:Thread-0-----i=0
    當前線程:Thread-2-----i=1
    當前線程:Thread-0-----i=1
    當前線程:Thread-1-----i=1
    當前線程:Thread-2-----i=2
    當前線程:Thread-1-----i=2
    當前線程:Thread-0-----i=2
    當前線程:Thread-2-----i=3
    當前線程:Thread-1-----i=3
    當前線程:Thread-0-----i=3
    當前線程:Thread-2-----i=4
    當前線程:Thread-0-----i=4
    當前線程:Thread-1-----i=4

    注:

    (1)通過運行代碼進行觀察,發現運行結果會等待一段時間,這就是sleep()方法讓原本處于運行狀態的線程進入了休眠,從而進程的狀態從運行狀態轉換為阻塞狀態。

    (2)以上代碼創建的三個線程肉眼觀察,發現它們好像是同時進入休眠狀態,但其實并不是同時休眠的。

    4.線程讓步------yield()方法

    線程讓步:暫停當前正在執行的線程對象,并執行其他線程。

    (1)調用yield()方法讓當前線程交出CPU權限,讓CPU去執行其他線程。

    (2)yield()方法和sleep()方法類似,不會釋放鎖,但yield()方法不能控制具體交出CPU的時間。

    (3)yield()方法只能讓擁有相同優先級的線程獲取CPU執行的機會。

    (4)使用yield()方法不會讓線程進入阻塞狀態,而是讓線程從運行狀態轉換為就緒狀態,只需要等待重新獲取CPU執行的機會。

    yield()方法:

    public static native void yield();

    關于yield()方法的操作如下:

    class MyThread implements Runnable{
    	@Override
    	public void run() {
    		for(int i=0;i<5;i++)
    		{
    			//使用Thread類的yield()方法
    			Thread.yield();
    			System.out.println("當前線程:"+Thread.currentThread().getName()+"-----i="+i);
    		}
    	}
    }
    public class Test1 {
    	public static void main(String[] args){
    		MyThread myThread=new MyThread();
    		//利用myThread對象分別創建三個線程
    		Thread thread1=new Thread(myThread);
    		thread1.start();
    		Thread thread2=new Thread(myThread);
    		thread2.start();
    		Thread thread3=new Thread(myThread);
    		thread3.start();
    	}
    }

    某次運行結果如下所示:

    當前線程:Thread-0-----i=0
    當前線程:Thread-0-----i=1
    當前線程:Thread-0-----i=2
    當前線程:Thread-0-----i=3
    當前線程:Thread-0-----i=4
    當前線程:Thread-1-----i=0
    當前線程:Thread-2-----i=0
    當前線程:Thread-2-----i=1
    當前線程:Thread-2-----i=2
    當前線程:Thread-2-----i=3
    當前線程:Thread-2-----i=4
    當前線程:Thread-1-----i=1
    當前線程:Thread-1-----i=2
    當前線程:Thread-1-----i=3
    當前線程:Thread-1-----i=4

    5. 等待線程終止------join()方法

    等待線程終止:指的是如果在主線程中調用該方法時就會讓主線程休眠,讓調用join()方法的線程先執行完畢后再開始執行主線程。

    join()方法:

     public final void join() throws InterruptedException {
            join(0);
        }

    注:上面的join()方法是不帶參數的,但join()方法還可以帶參數,下去自行了解!

    關于join()方法的操作如下:

    class MyThread implements Runnable{
    	@Override
    	public void run() {
    		for(int i=0;i<2;i++)
    		{
    			//使用Thread類的sleep()方法
    			try {
    				Thread.sleep(3000);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			System.out.println("當前線程:"+Thread.currentThread().getName()+"-----i="+i);
    		}
    	}
    }
    public class Test1 {
    	public static void main(String[] args) throws InterruptedException{
    		MyThread myThread=new MyThread();
    		Thread thread1=new Thread(myThread,"自己創建的線程");
    		thread1.start();
    		System.out.println("主線程:"+Thread.currentThread().getName());
    		//線程對象thread1調用join()方法
    		thread1.join();
    		System.out.println("代碼結束");
    	}
    }

    運行結果如下所示:

    主線程:main
    當前線程:自己創建的線程-----i=0
    當前線程:自己創建的線程-----i=1
    代碼結束

    若不調用join()方法的話,運行結果如下所示:

    主線程:main
    代碼結束
    當前線程:自己創建的線程-----i=0
    當前線程:自己創建的線程-----i=1

    故通過兩個運行結果可以更加深刻地感受到調用join()方法后的作用!調用join()方法和不調用join()方法的區別!

    6. 線程停止

    多線程中停止線程有三種方式:

    (1)設置標記位,讓線程正常停止。

    class MyThread implements Runnable{
    	//設置標記位
    	private boolean flag=true;
    	public void setFlag(boolean flag) {
    		this.flag = flag;
    	}
    	@Override
    	public void run() {
    		int i=0;
    		while(flag)
    		{
    			System.out.println("第"+(i++)+"次執行-----"+"線程名稱:"+Thread.currentThread().getName());
    		}
    	}
    }
    public class Test1 {
    	public static void main(String[] args) throws InterruptedException{
    		MyThread myThread=new MyThread();
    		Thread thread1=new Thread(myThread,"自己創建的線程");
    		thread1.start();
    		//讓主線程sleep一毫秒
    		Thread.sleep(1);
    		//修改標記位的值,讓自己創建的線程停止
    		myThread.setFlag(false);
    		System.out.println("代碼結束");
    	}
    }

    運行結果如下所示:

    第0次執行-----線程名稱:自己創建的線程
    第1次執行-----線程名稱:自己創建的線程
    第2次執行-----線程名稱:自己創建的線程
    第3次執行-----線程名稱:自己創建的線程
    第4次執行-----線程名稱:自己創建的線程
    第5次執行-----線程名稱:自己創..............
    第19次執行-----線程名稱:自己創建的線程
    第20次執行-----線程名稱:自己創建的線程
    第21次執行-----線程名稱:自己創建的線程
    第22次執行-----線程名稱:自己創建的線程
    第23次執行-----線程名稱:自己創建的線程
    第24次執行-----線程名稱:自己創建的線程
    第25次執行-----線程名稱:自己創建的線程
    第26次執行-----線程名稱:自己創建的線程
    代碼結束

    (2)使用stop()方法強制使線程退出,但是使用該方法不安全,已經被廢棄了!

    class MyThread implements Runnable{
    	@Override
    	public void run() {
    		for(int i=0;i<100;i++)
    		{
    			System.out.println("線程名稱:"+Thread.currentThread().getName()+"------i="+i);
    		}
    	}
    }
    public class Test1 {
    	public static void main(String[] args) throws InterruptedException{
    		MyThread myThread=new MyThread();
    		Thread thread1=new Thread(myThread,"自己創建的線程");
    		thread1.start();
    		//讓主線程sleep一毫秒
    		Thread.sleep(1);
    		//調用已被棄用的stop()方法去強制讓線程退出
    		thread1.stop();
    		System.out.println("代碼結束");
    	}
    }

    某次運行結果如下所示:

    線程名稱:自己創建的線程------i=0
    線程名稱:自己創建的線程------i=1
    線程名稱:自己創建的線程------i=2
    線程名稱:自己創建的線程------i=3
    線程名稱:自己創建的線程------i=4
    線程名稱:自己創建的線程------i=5
    線程名稱:自己創建的線程------i=6
    ......
    線程名稱:自己創建的線程------i=28
    線程名稱:自己創建的線程------i=29
    線程名稱:自己創建的線程------i=30
    線程名稱:自己創建的線程------i=31
    線程名稱:自己創建的線程------i=48
    線程名稱:自己創建的線程------i=49
    線程名稱:自己創建的線程------i=50
    線程名稱:自己創建的線程------i=51線程名稱:自己創建的線程------i=51代碼結束

    從上述代碼和運行結果可以看出,原本線程對象thread1的run()方法中應該執行100次語句“System.out.println(“線程名稱:”+Thread.currentThread().getName()+"------i="+i);”,但現在沒有執行夠100次,所以說stop()方法起到了讓線程終止的作用。再從運行結果上可以看出,i=51被執行了兩次且沒有換行,這就體現了調用stop()方法的不安全性!

    下面正式地解釋stop()方法為什么不安全?

    因為stop()方法會解除由線程獲得的所有鎖,當在一個線程對象上調用stop()方法時,這個線程對象所運行的線程會立即停止,假如一個線程正在執行同步方法:

    public synchronized void fun(){
    	x=3;
    	y=4;
    }

    由于方法是同步的,多線程訪問時總能保證x,y被同時賦值,而如果一個線程正在執行到x=3;時,被調用的stop()方法使得線程即使在同步方法中也要停止,這就造成了數據的不完整性。故,stop()方法不安全,已經被廢棄,不建議使用!

    (3)使用Thread類的interrupt()方法中斷線程。

    class MyThread implements Runnable{
    	@Override
    	public void run() {
    		int i=0;
    		while(true)
    		{
    			//使用sleep()方法,使得線程由運行狀態轉換為阻塞狀態
    			try {
    				Thread.sleep(1000);
    				//調用isInterrupted()方法,用于判斷當前線程是否被中斷
    				boolean bool=Thread.currentThread().isInterrupted();
    				if(bool) {
    					System.out.println("非阻塞狀態下執行該操作,當前線程被中斷!");
    					break;
    				}
    				System.out.println("第"+(i++)+"次執行"+" 線程名稱:"+Thread.currentThread().getName());
    			} catch (InterruptedException e) {
    				System.out.println("退出了!");
    				//這里退出了阻塞狀態,且中斷標志bool被系統自動清除設置為false,所以此處的bool為false
    				boolean bool=Thread.currentThread().isInterrupted();
    				System.out.println(bool);
    				//退出run()方法,中斷進程
    				return;
    			}
    		}
    	}
    }
    public class Test1 {
    	public static void main(String[] args) throws InterruptedException{
    		MyThread myThread=new MyThread();
    		Thread thread1=new Thread(myThread,"自己創建的線程");
    		thread1.start();
    		//讓主線程sleep三秒
    		Thread.sleep(3000);
    		//調用interrupt()方法
    		thread1.interrupt();
    		 System.out.println("代碼結束");
    	}
    }

    運行結果如下所示 :

    第0次執行 線程名稱:自己創建的線程
    第1次執行 線程名稱:自己創建的線程
    第2次執行 線程名稱:自己創建的線程
    代碼結束
    退出了!
    false

    (1)interrupt()方法只是改變中斷狀態而已,它不會中斷一個正在運行的線程。具體來說就是,調用interrupt()方法只會給線程設置一個為true的中斷標志,而設置之后,則根據線程當前狀態進行不同的后續操作。

    (2)如果線程的當前狀態出于非阻塞狀態,那么僅僅將線程的中斷標志設置為true而已;

    (3)如果線程的當前狀態出于阻塞狀態,那么將在中斷標志設置為true后,還會出現wait()、sleep()、join()方法之一引起的阻塞,那么會將線程的中斷標志位重新設置為false,并拋出一個InterruptedException異常。

    (4)如果在中斷時,線程正處于非阻塞狀態,則將中斷標志修改為true,而在此基礎上,一旦進入阻塞狀態,則按照阻塞狀態的情況來進行處理。例如,一個線程在運行狀態時,其中斷標志設置為true之后,一旦線程調用了wait()、sleep()、join()方法中的一種,立馬拋出一個InterruptedException異常,且中斷標志被程序自動清除,重新設置為false。

    總結:調用Thread類的interrupted()方法,其本質只是設置該線程的中斷標志,將中斷標志設置為true,并根據線程狀態決定是否拋出異常。因此,通過interrupted()方法真正實現線程的中斷原理是 :開發人員根據中斷標志的具體值來決定如何退出線程。

    7. 線程等待------wait()方法

    首先,wait()方法是Object類的方法,下面是無參的wait()方法:

    public final void wait() throws InterruptedException {
            wait(0);
        }

    (1)wait()方法的作用是讓當前正在執行的線程進入線程阻塞狀態的等待狀態,該方法時用來將當前線程置入“預執行隊列”中,并且調用wait()方法后,該線程在wait()方法所在的代碼處停止執行,直到接到一些通知或被中斷為止。

    (2)wait()方法只能在同步代碼塊或同步方法中調用,故如果調用wait()方法時沒有持有適當的鎖時,就會拋出異常。

    (3)wait()方法執行后,當前線程釋放鎖并且與其他線程相互競爭重新獲得鎖。

    下面調用wait()方法:

    public class Test1 {
    	public static void main(String[] args) {
    		Object object=new Object();
    		synchronized (object) {
    			System.out.println("調用wait()前");
    			//調用Object類的wait()方法
    			try {
    				object.wait();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			System.out.println("調用wait()后");
    		}
    	} 
    }

    運行結果如下所示:

    調用wait()前

    解析:此時,程序依然處于執行狀態。原本應該打印兩條語句:調用wait()前 調用wait()后,但是由于該程序還沒有運行完而且只打印了一條語句:調用wait()前。這是因為什么呢?因為調用了Object類的wait()方法,使得程序在執行wait()方法之后一直等待下去,故只執行了調用wait()方法前的語句。但程序不能這樣一直等待下去,這個時候就需要另一個方法去喚醒調用wait()方法的處于等待狀態的線程,讓等待線程繼續執行下去,該方法為notify()方法。

    8. 線程喚醒-------notify()方法

    首先,notify()方法也是Object類的方法:

    public final native void notify();

    (1)notify()方法要在同步代碼塊或同步方法中調用。

    (2)notify()方法是用來通知那些等待該對象的對象鎖的線程,對其調用wait()方法的對象發出通知讓這些線程不再等待,繼續執行。

    (3)如果有多個線程都在等待,則由線程規劃器隨機挑選出一個呈wait狀態的線程將其線程喚醒,繼續執行該線程。

    (4)調用notify()方法后,當前線程并不會馬上釋放該對象鎖,要等到執行notify()方法的線程執行完才會釋放對象鎖。

    下面調用notify()方法:

    class MyThread implements Runnable{
    	private boolean flag;
    	private Object object;
    	//定義一個構造方法
    	public MyThread(boolean flag,Object object) {
    		this.flag=flag;
    		this.object=object;
    	}
    	//定義一個普通方法,其中調用了wait()方法
    	public void waitThread() {
    		synchronized (this.object) {
    			try {
    				System.out.println("調用wait()前------"+Thread.currentThread().getName());
    				//調用wait()方法
    				this.object.wait();
    				System.out.println("調用wait()后------"+Thread.currentThread().getName());
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	//定義一個普通方法,其中調用了notify()方法
    	public void notifyThread() {
    		synchronized (this.object) {
    			try {
    				System.out.println("調用notify前------"+Thread.currentThread().getName());
    				//調用notify()方法
    				this.object.notify();
    				System.out.println("調用notify()后------"+Thread.currentThread().getName());
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	@Override
    	public void run() {
    		if(this.flag) {
    			this.waitThread();
    		}else {
    			this.notifyThread();
    		}
    	}	
    }
    public class Test1 {
    	public static void main(String[] args) {
    		Object object=new Object();
    		//實例化調用wait()的線程
    		MyThread wait=new MyThread(true,object);
    		Thread waitThread=new Thread(wait,"wait線程");
    		//實例化調用notify()的線程
    		MyThread notify=new MyThread(false,object);
    		Thread notifyThread=new Thread(notify,"notify線程");
    		//啟動線程
    		waitThread.start();
    		//調用一下sleep()方法,使得查看效果更明顯
    		try {
    			Thread.sleep(2000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		notifyThread.start();
    	} 
    }

    運行結果

    調用wait()前------wait線程
    調用notify前------notify線程
    調用notify()后------notify線程
    調用wait()后------wait線程

    解析:根據run方法及實例化的線程對象,wait線程執行了waitThread()方法,該方法中調用了wait()方法使得線程進入線程阻塞狀態的等待狀態并釋放鎖,如果沒有其他線程去喚醒該線程的話wait線程將一直等待下去。此時,notify線程執行了notifyThread()方法,該方法中調用了notify()方法,使得notify線程去喚醒wait線程,讓wait線程不再等待下去,并且先將notify線程執行完后釋放鎖再執行wait線程的wait()方法之后的語句。所以打印如上所示。

    但要注意的是,當有多個線程處于等待時,調用notify()方法喚醒線程時,就會依然有線程處于等待狀態,演示如下:

    class MyThread implements Runnable{
    	private boolean flag;
    	private Object object;
    	//定義一個構造方法
    	public MyThread(boolean flag,Object object) {
    		this.flag=flag;
    		this.object=object;
    	}
    	//定義一個普通方法,其中調用了wait()方法
    	public void waitThread() {
    		synchronized (this.object) {
    			try {
    				System.out.println("調用wait()前------"+Thread.currentThread().getName());
    				//調用wait()方法
    				this.object.wait();
    				System.out.println("調用wait()后------"+Thread.currentThread().getName());
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	//定義一個普通方法,其中調用了notify()方法
    	public void notifyThread() {
    		synchronized (this.object) {
    			try {
    				System.out.println("調用notify前------"+Thread.currentThread().getName());
    				//調用notify()方法
    				this.object.notify();
    				System.out.println("調用notify()后------"+Thread.currentThread().getName());
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	@Override
    	public void run() {
    		if(this.flag) {
    			this.waitThread();
    		}else {
    			this.notifyThread();
    		}
    	}	
    }
    public class Test1 {
    	public static void main(String[] args) {
    		Object object=new Object();
    		//實例化調用wait()的線程
    		MyThread wait=new MyThread(true,object);
    		Thread waitThread1=new Thread(wait,"wait線程1");
    		Thread waitThread2=new Thread(wait,"wait線程2");
    		Thread waitThread3=new Thread(wait,"wait線程3");
    		//實例化調用notify()的線程
    		MyThread notify=new MyThread(false,object);
    		Thread notifyThread=new Thread(notify,"notify線程");
    		//啟動3個等待線程
    		waitThread1.start();
    		waitThread2.start();
    		waitThread3.start();
    		//調用一下sleep()方法,使得查看效果更明顯
    		try {
    			Thread.sleep(2000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		notifyThread.start();
    	} 
    }

    運行結果如下所示:

    調用wait()前------wait線程1
    調用wait()前------wait線程3
    調用wait()前------wait線程2
    調用notify前------notify線程
    調用notify()后------notify線程
    調用wait()后------wait線程1

    此時程序并沒有執行完畢,因為依然有線程處于等待狀態,所以notify()只是隨機將某一個等待線程喚醒,并沒有喚醒所有等待線程。那么,若有多個線程處于等待狀態時,如何將所有等待線程都喚醒呢?下面將介紹notifyAll()方法

    9. notifyAll()方法

    Object類的notifyAll()方法:

    public final native void notifyAll();

    notifyAll()方法將同一對象鎖的所有等待線程全部喚醒。代碼演示如下:

    class MyThread implements Runnable{
    	private boolean flag;
    	private Object object;
    	//定義一個構造方法
    	public MyThread(boolean flag,Object object) {
    		this.flag=flag;
    		this.object=object;
    	}
    	//定義一個普通方法,其中調用了wait()方法
    	public void waitThread() {
    		synchronized (this.object) {
    			try {
    				System.out.println("調用wait()前------"+Thread.currentThread().getName());
    				//調用wait()方法
    				this.object.wait();
    				System.out.println("調用wait()后------"+Thread.currentThread().getName());
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	//定義一個普通方法,其中調用了notifyAll()方法
    	public void notifyThread() {
    		synchronized (this.object) {
    			try {
    				System.out.println("調用notify前------"+Thread.currentThread().getName());
    				//調用notifyAll()方法
    				this.object.notifyAll();
    				System.out.println("調用notify()后------"+Thread.currentThread().getName());
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	@Override
    	public void run() {
    		if(this.flag) {
    			this.waitThread();
    		}else {
    			this.notifyThread();
    		}
    	}	
    }
    public class Test1 {
    	public static void main(String[] args) {
    		Object object=new Object();
    		//實例化調用wait()的線程
    		MyThread wait=new MyThread(true,object);
    		Thread waitThread1=new Thread(wait,"wait線程1");
    		Thread waitThread2=new Thread(wait,"wait線程2");
    		Thread waitThread3=new Thread(wait,"wait線程3");
    		//實例化調用notifyAll()的線程
    		MyThread notify=new MyThread(false,object);
    		Thread notifyThread=new Thread(notify,"notify線程");
    		//啟動3個等待線程
    		waitThread1.start();
    		waitThread2.start();
    		waitThread3.start();
    		//調用一下sleep()方法,使得查看效果更明顯
    		try {
    			Thread.sleep(2000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		notifyThread.start();
    	} 
    }

    運行結果如下所示:

    調用wait()前------wait線程1
    調用wait()前------wait線程2
    調用wait()前------wait線程3
    調用notify前------notify線程
    調用notify()后------notify線程
    調用wait()后------wait線程3
    調用wait()后------wait線程2
    調用wait()后------wait線程1

    解析:此時,程序執行完畢,所有等待線程都被調用notifyAll()方法的具有同一對象鎖的線程喚醒,故每一個等待線程都會在調用wait()后繼續執行直到該線程結束。

    JAVA多線程有哪幾種實現方式?

    1. 繼承Thread類

    1)定義Thread類的子類,并重寫Thread類的run()方法。

    2)創建Thread子類的實例,及創建了線程對象。

    3)調用線程對象的start()方法來啟動該線程。

    class MyThread extends Thread{
    	public void run(){
    		System.out.println("線程運行");
    	}
    }
    public class Test{
    	public static void main(String[] args){
    		MyThread thread=new MyThread();
    		thread.start();//開啟線程
    	}
    }

    Thread類常用方法

    Thread.currentThread():是Thread類的靜態方法,該方法總是返回當前正在執行的線程對象。

    String getName():該方法是Thread類的實例方法,是返回調用該方法的線程名字。

    2. 實現Runnable接口

    1)定義Runnable接口的實現類,并重寫該接口的run()方法,該run()方法同樣是線程執行體。

    2)創建Runnable實現類的實例,并以此實例作為Thread的target來創建Thread對象,該Thread對象才是真正的線程對象。

    3)調用線程對象的start()方法來啟動該線程。

    class Runna implements Runnable
    {
    	public void run(){
    		System.out.println("線程運行");
    	}
    }
    public class Test{
    	public static void main(String[] args){
    		Runna runna=new Runna();
    		Thread t=new Thread(runna);
    		t.start();//開啟線程
    	}
    }

    推薦使用那種:很明顯,我們在使用繼承Thread方式時,有一個很大的缺點,就是我們繼承了Thread后就不能繼承其他類了。但是如果我們實現Runnable的話,恰好可以解決這個問題。

    • 一個類只能extends一個父類,但可以implements多個接口。

    • 一個接口則可以同時extends多個接口,卻不能implements任何接口。

    3. 使用Callable 和 FutureTask 創建線程

    1)創建Callable 接口的實現類,并實現 call() 方法,該 call() 方法將作為線程執行體,且該 call() 方法有返回值 。

    2)創建Callable 實現類的實例,使用 FutureTask 類來包裝 Callable 對象, 該 FutrueTask 對象封裝了該 Callable 對象的 call() 方法的返回值。

    3)使用 FutureTask 對象作為 Thread 對象的 target 創建并啟動新線程。

    4)調用FutureTask 對象的 get() 方法來獲得子線程執行結束后的返回值。

    public class ThreadDemo03 {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    
            Callable<Object> oneCallable = new Tickets<Object>();
            FutureTask<Object> oneTask = new FutureTask<Object>(oneCallable);
    
            Thread t = new Thread(oneTask);
    
            System.out.println(Thread.currentThread().getName());
    
            t.start();
    
        }
    
    }
    
    class Tickets<Object> implements Callable<Object>{
    
        //重寫call方法
        @Override
        public Object call() throws Exception {
            // TODO Auto-generated method stub
            System.out.println(Thread.currentThread().getName()+"-->我是通過實現Callable接口通過FutureTask包裝器來實現的線程");
            return null;
        }   
    }

    4. 通過線程池創建線程(使用ExecutorService、Callable、Future實現有返回結果的多線程。)

    ExecutorService、Callable都是屬于Executor框架。返回結果的線程是在JDK1.5中引入的新特征,還有Future接口也是屬于這個框架,有了這種特征得到返回值就很方便了。

    通過分析可以知道,他同樣也是實現了Callable接口,實現了Call方法,所以有返回值。這也就是正好符合了前面所說的兩種分類

    執行Callable任務后,可以獲取一個Future的對象,在該對象上調用get就可以獲取到Callable任務返回的Object了。get方法是阻塞的,即:線程無返回結果,get方法會一直等待。

    public class ThreadDemo05{
    
        private static int POOL_NUM = 10;     //線程池數量
    
        /**
         * @param args
         * @throws InterruptedException 
         */
        public static void main(String[] args) throws InterruptedException {
            // TODO Auto-generated method stub
            ExecutorService executorService = Executors.newFixedThreadPool(5);  
            for(int i = 0; i<POOL_NUM; i++)  
            {  
                RunnableThread thread = new RunnableThread();
    
                //Thread.sleep(1000);
                executorService.execute(thread);  
            }
            //關閉線程池
            executorService.shutdown(); 
        }   
    
    }
    
    class RunnableThread implements Runnable  
    {     
        @Override
        public void run()  
        {  
            System.out.println("通過線程池方式創建的線程:" + Thread.currentThread().getName() + " ");  
    
        }  
    }

    程序運行結果:

    通過線程池方式創建的線程:pool-1-thread-3
    通過線程池方式創建的線程:pool-1-thread-4
    通過線程池方式創建的線程:pool-1-thread-1
    通過線程池方式創建的線程:pool-1-thread-5
    通過線程池方式創建的線程:pool-1-thread-2
    通過線程池方式創建的線程:pool-1-thread-5
    通過線程池方式創建的線程:pool-1-thread-1
    通過線程池方式創建的線程:pool-1-thread-4
    通過線程池方式創建的線程:pool-1-thread-3
    通過線程池方式創建的線程:pool-1-thread-2

    以上是“Java之多線程方法狀態和創建方法的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    灵宝市| 乡城县| 香河县| 天柱县| 汝南县| 定远县| 鄂尔多斯市| 泽州县| 县级市| 英吉沙县| 洱源县| 德庆县| 鄂托克前旗| 道真| 新乡市| 图木舒克市| 莱阳市| 格尔木市| 林西县| 北安市| 宜城市| 县级市| 乌拉特前旗| 新干县| 龙岩市| 揭阳市| 灵寿县| 城市| 青海省| 洛浦县| 绥德县| 大理市| 都江堰市| 宁阳县| 德兴市| 镇康县| 罗山县| 平顺县| 怀安县| 苏尼特右旗| 铜川市|