多線程demo理解

翻書:哦,馬冬梅

合書:馬什麼梅?

翻書:哦,馬冬梅?

合書:馬東什麼?

翻書:哦,馬冬梅啊

合書:什麼東梅?

多線程,很多人聽到就頭疼的東西(我聽到也頭疼)但是還是決定準備寫下來加深一下理解吧。

一、啥是多線程

首先,先來一點文鄒鄒的東西,一個程序是一個進程 ,一個進程至少有一個線程,而線程是操作系統可識別的最小執行和調度單位。而多線程是多個線程併發執行。

eg:如果樓下食堂是一個系統的話,你火急火燎的去喫飯,等待(手抖的)阿姨給你打菜,但是樓下的隊伍長的出奇,這讓你很不開心讓來喫飯的人也都很不開心,於是乎食堂老闆含淚多招了幾位阿姨來一起給你們打菜。這就可以理解爲多條線程併發執行任務。

二、如何創建線程

1.一個類繼承Thread類,並重寫裏面的run()方法。

2.一個類去實現Runnable接口,並實現裏面的run()方法。

3.創建一個線程池,併線程池中直接獲取一個線程。

一般常用的是第二種,因爲java只能單繼承但是可以多實現

三、代碼實例

首先我們設計大家普遍運用的場景:

很前一段時間復聯4上映了,那叫一個火啊,其中鋼鐵俠、美國隊長、雷神。。。。差點跑題了。這麼火的電影首映當然得靠搶啊,這一天萬達影城預售100張票,由三個自助售票機售賣。於是乎我們有了如下代碼:

ThreadDemo.java

public class ThreadDemo implements Runnable{
	
	//預售100張
	private int tickets = 100;
	
	@Override
	public void run() {
		while (true) {
			if (tickets > 0) {
				System.out.println(Thread.currentThread().getName() + "正在售賣第" + (tickets--) + "張票");
			}else{
				return;
			}
		}
	}

}

SellTicketDemo.java

public class SellTicketDemo {
	public static void main(String[] args) {
		ThreadDemo demo = new ThreadDemo();
		Thread t1 = new Thread(demo,"售票機1號");
		Thread t2 = new Thread(demo,"售票機2號");
		Thread t3 = new Thread(demo,"售票機3號");
		t1.start();
		t2.start();
		t3.start();
	}
}

執行main結果如圖:

好像沒什麼問題,但是這是在我的測試中,實際生活中由於網絡原因肯定會出現一點延遲情況,下面我在run方法中添加一丟丟延遲(加100毫秒,很短的延遲了 )

ThreadDemo.java

public class ThreadDemo implements Runnable{
	
	//預售100張
	private int tickets = 100;
	
	@Override
	public void run() {
		while (true) {
			if (tickets > 0) {
				System.out.println(Thread.currentThread().getName() + "正在售賣第" + (tickets--) + "張票");
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}else{
				return;
			}
		}
	}
}

結果:

出現了一票多賣的情況,因爲延遲的原因導致線程之間的數據沒有及時同步導致的。這個時候就需要引入一個同步機制,也就是synchronized關鍵字

public class ThreadDemo implements Runnable{
	
	//預售100張
	private int tickets = 100;
	
	@Override
	public void run() {
		while (true) {
			synchronized (this) {
				if (tickets > 0) {
					System.out.println(Thread.currentThread().getName() + "正在售賣第" + (tickets--) + "張票");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}else{
					return;
				}
			}
		}
	}
}

如圖已經正常。但是看起來又不像那麼正常,感覺售票機2號好像沒工作,其實並不是,因爲有很大可能在線程1執行run的時候在while裏面執行if,這時已經鎖住了,線程2和3無法操作,但是當if執行結束後釋放鎖,但是緊接着第二波的循環過來了,第二波循環到來的比線程2、3獲取的快,就會導致執行結果爲某一條線程消耗了所有票,結果可能會誤導一些人們,其實事實上程序並沒錯只是其他獲取鎖沒有循環來的快而導致的。可以在if後加上一個短暫延遲,便於測試與理解。

代碼實例:

public class ThreadDemo implements Runnable{
	
	private int tickets = 100;
	

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + "執行run方法");
		while (true) {
			synchronized (this) {
				System.out.println(Thread.currentThread().getName() + "上鎖");
				if (tickets > 0) {
					try {
						// 延遲
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "正在消耗第" + (tickets--) + "條數據");
				}else{
					System.out.println(Thread.currentThread().getName() + "沒數據了");
					return;
				}
				System.out.println(Thread.currentThread().getName() + "即將解鎖");
			}
			try {
				//延遲100毫秒讓其他線程進入
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
		}
	}
}
public class SellTicketDemo {
	public static void main(String[] args) {
		ThreadDemo demo = new ThreadDemo();
		Thread t1 = new Thread(demo,"線程1");
		Thread t2 = new Thread(demo,"線程2");
		Thread t3 = new Thread(demo,"線程3");
		t1.start();
		System.out.println("線程1已啓動");
		t2.start();
		System.out.println("線程2已啓動");
		t3.start();
		System.out.println("線程3已啓動");
	}
}

合書:嗯,馬冬梅。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章