第一種方式:通過繼承Thread類創建
new Thread() {// new Threah(){}表示創建一個匿名子類的實例對象,{}內是子類的代碼
// 重寫父類的run方法
public void run() {
while (true) {
try {// 必需try...catch
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}.start();
第二種方式:通過實現Runnable接口創建
// new Thread(new Runnable(){}).start();表示調用Threah對象接受的Runnable對象的run方法.
new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}).start();
Thread內部run方法的代碼:
public void run() {
if (target != null) {
target.run();
}
}
target 是Runnable子類的實例對象,若通過Thread子類實現,則優先調用子類的run方法.其實Thread類也是實現了 Runnable接口.
使用第二種方式創建的好處:
1、 多個線程共享同一份資源
2、可以避免由於java單繼承特性帶來的侷限性。
無論是繼承還是實現都需要重寫run方法,此方法爲線程的主體.
模擬多個線程共享同一份資源
問題:一個火車站當天去往某地的車票一共有50張,由多個售票點負責售票.
若通過繼承方式如下:
class Demo extends Thread
{
private int ticket = 50 ;
public void run()
{
while(this.ticket>0)
{
System.out.println("賣票:"+this.ticket--) ;
}
}
};
public class ThreadDemo04
{
public static void main(String args[])
{
// 準備四個售票點
Demo d1 = new Demo() ;
Demo d2 = new Demo() ;
Demo d3 = new Demo() ;
Demo d4 = new Demo() ;
d1.start() ;
d2.start() ;
d3.start() ;
d4.start() ;
}
};
但這樣打印的結果是:每個售票點都售票50張,不符合實際要求!當然你可以把ticket設置成爲static,這樣也可以符合要求.
第二種方式:
class Demo05 implements Runnable
{
private int ticket = 50 ;
public void run()
{
while(this.ticket>0)
{
System.out.println("賣票:"+this.ticket--) ;
}
}
};
public class ThreadDemo05
{
public static void main(String args[])
{
// 四個售票點應該控制同一個資源:50
Demo05 d = new Demo05() ;
Thread t1 = new Thread(d) ;
Thread t2 = new Thread(d) ;
Thread t3 = new Thread(d) ;
Thread t4 = new Thread(d) ;
t1.start() ;
t2.start() ;
t3.start() ;
t4.start() ;
}
};
由於不同的線程調用的是同一個對象(Demo05 d = new Demo05() )的run方法,因此訪問的ticket 都是同一個對象的成員屬性.
但這兩份代碼都存在線程安全問題:ticket到最後可能會變成一個負數,如在while循環開始加一段:
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
這樣ticket最後打印的值就會出現負數! 解決的方法線程同步.在下一節裏講