翻書:哦,馬冬梅
合書:馬什麼梅?
翻書:哦,馬冬梅?
合書:馬東什麼?
翻書:哦,馬冬梅啊
合書:什麼東梅?
多線程,很多人聽到就頭疼的東西(我聽到也頭疼)但是還是決定準備寫下來加深一下理解吧。
一、啥是多線程
首先,先來一點文鄒鄒的東西,一個程序是一個進程 ,一個進程至少有一個線程,而線程是操作系統可識別的最小執行和調度單位。而多線程是多個線程併發執行。
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已啓動");
}
}
合書:嗯,馬冬梅。