創建多線程的幾種方式

第一種方式:通過繼承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最後打印的值就會出現負數!  解決的方法線程同步.在下一節裏講

 

發佈了15 篇原創文章 · 獲贊 3 · 訪問量 2098
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章