[Java][實現多執行緒的三種方式]
目錄
本系列學習筆記簡介
傳智播客的畢向東Java基礎教程是免費公開的一份面向初學者的Java學習教程。在我學習畢老師的Java基礎教程過程中,苦於其並沒有附帶練習題,總覺得學的‘輕飄飄’的,所以決定每天看完的一些內容,總在接下來的幾天裡找一些時間寫下來,看看自己還記得多少,看看自己哪些知識點理解的不透徹。希望本系列學習筆記在幫助自己理清思路,理順知識點的同時,也能夠幫助其他在學習Java的同學。歡迎大家在評論區討論相關內容。
多執行緒的繼承Thread類實現
程序執行緒簡介
程序可以認為是一個正在執行中的程式,你開啟工作管理員就可以看到程序。而執行緒是這個程序中,為了完成一些任務而相互獨立進行的程式碼集合,比如你在360安全衛士中開啟安全檢查的同時又可以清掃垃圾,這時你就開啟了兩個執行緒。
多執行緒賣票介紹
我們這裡通過一個賣票例子來講解多執行緒的繼承Thread類實現。我們假設共有100張編號為1到100的票,在命令列列印一個數字就視為賣出了對應編號的票,我們首先採用繼承Thread類來實現。
思路:建立一個類來繼承Thread類,在子類中重寫run()方法來覆蓋父類Thread中的run()方法。
程式碼塊
錯誤程式碼塊
class Ticket extends Thread
{
private int num = 100;
public void run()
{
while(true)
{
if(num>0)
System.out.println(Thread.currentThread().getName()+"....."+"num="+num--);
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Ticket t1 = new Ticket( );
Ticket t2 = new Ticket();
t1.start();
t2.start();
}
}
上述程式碼的部分執行結果為:
我們看到執行緒0與執行緒1賣出了同樣的票號,這是我們不希望看到的,這100號座位旅客0坐還是旅客1坐合適啊?究其原因,是因為我們new了兩個Ticket物件,每生成一個Ticket物件,JVM虛擬機器的堆記憶體中都會有屬於該物件的成員變數num=100,所以num- -的時候每個票號都會出現兩次。我們可以選擇把num變為靜態變數,這樣它就會被JVM儲存在方法區中,被Ticket物件所共享。
正確程式碼塊
class Ticket extends Thread
{
private static int num = 100;//我們只是在這裡加上了static關鍵字
public void run()
{
while(true)
{
if(num>0)
System.out.println(Thread.currentThread().getName()+"....."+"num="+num--);
}
}
}
class TicketDemo
{
public static void main(String[] args)
{
Ticket t1 = new Ticket();
Ticket t2 = new Ticket();
t1.start();
t2.start();
}
}
注意:這個所謂的正確程式碼塊,還是存在安全隱患的,因為如果執行緒0執行到num=1到了判斷語句之後,這時如果執行緒1進來,那麼會輸出Thread=1…num=1,隨後切換到執行緒0,輸出就會為Thread=0…num=0
通過介面Runnable實現多執行緒
由於Java不允許多繼承,所以當一個類已經有父類時就不能夠繼承Thread類了,這時要通過介面Runnable實現多執行緒。使用實現介面Runnable的物件建立執行緒,當啟動執行緒時,在獨立執行的執行緒中就會呼叫物件的run方法。
程式碼塊
class ThreadDemo
{
public static void main(String[] args)
{
Ticket t = new Ticket();
// 使用實現Runnable介面的物件建立一個執行緒
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
//啟動該執行緒,將導致在獨立執行的執行緒中呼叫該物件的run方法
t1.start();
t2.start();
}
}
class Ticket implements Runnable
{
public int num=100;
public void run()
{
while(true)
{
if(num>0)
System.out.println(Thread.currentThread().getName()+"..."+num--);
}
}
}
命令列執行結果為
最後要注意的幾點:
1.上述實現多執行緒是不安全的,還需要通過同步關鍵字synchronized來保證安全。
2.實現多執行緒常見的有三種方式,這裡介紹了通過繼承Thread類實現,通過實現介面Runnable實現,最後一種我們有機會再說。