【從零開始學Java筆記】多線程

2020-04-07 16:06:21來源:博客園 閱讀 ()

容器云強勢上線!快速搭建集群,上萬Linux鏡像隨意使用

【從零開始學Java筆記】多線程

大家可以關注作者的賬號,關注從零開始學Java筆記文集。也可以根據目錄前往作者的博客園博客進行學習。本片文件將基于黑馬程序員就業班視頻進行學習以及資料的分享,并記錄筆記和自己的看法。歡迎大家一起學習和討論。

【從零開始學Java筆記】目錄

進程和線程的區別

進程:是執行中一段程序,即一旦程序被載入到內存中并準備執行,它就是一個進程。進程是表示資源分配的的基本概念,又是調度運行的基本單位,是系統中的并發執行的單位。
線程:單個進程中執行中每個任務就是一個線程。線程是進程中執行運算的最小單位。
一個進程可以有一個線程,也可以有多個線程

單線程和多線程的優缺點

單線程:安全性高,但是效率低
多線程:安全性低,效率高
多線程案例: 360,迅雷等

Thread類

創建線程的方法一

先創建一個類,繼承Thread類,并且重寫run方法。

public class MyThread extends Thread{
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(getName()+i);
		}
	}
}

在主函數里面調用MyThread類,然后使用start()方法即可調用。

public class ThreadDemo {
	public static void main(String[] args) {
		//創建一個線程
		MyThread mt = new MyThread();
		mt.setName("Thread-1:");
		mt.start();
		
		//創建另一個線程
		MyThread mt2 = new MyThread();
		mt2.setName("Thread-2:");
		mt2.start();
 	}

}

輸出結果(部分)如下

可以看出線程一和線程二交替出現,這是因為計算機處理兩個同時運行的線程時,用極短的時間在兩個線程間切換,隨機調用。但速度極快,無法察覺到。

創建線程的方法二

創建線程的另一種方法是聲明實現 Runnable 接口的類。該類然后實現 run 方法。然后可以分配該類的實例,在創建 Thread 時作為一個參數來傳遞并啟動。

public class MyThread2 implements Runnable{

	@Override
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println(Thread.currentThread().getName() + i);
		}
	}

}
public class ThreadDemo2 {
	public static void main(String[] args) {
		MyThread2 mt = new MyThread2();
		Thread t = new Thread(mt);
		t.setName("Thread-1:");
		t.start();
		
		MyThread2 mt2 = new MyThread2();
		Thread t2 = new Thread(mt);
		t2.setName("Thread-2:");
		t2.start();
		
	}

}

輸出結果(部分)與之前的輸出結果相似

模擬火車站售票

1.先創建線程類
要求:100張票,持續售票,票數為0停止售票。

public class ThreadTicket implements Runnable {

	private static int ticketNum = 100;

	@Override
	public void run() {
		while (true) {
			if (ticketNum > 0) {
				System.out.println(Thread.currentThread().getName() + ":" + ticketNum--);
			}
		}

	}

	public static int getTicketnum() {
		return ticketNum;
	}

}

主函數

public class ThreadTicketDemo {
	public static void main(String[] args) {
		ThreadTicket tt = new ThreadTicket();
		Thread t1 = new Thread(tt);
		t1.setName("售票口1");
		t1.start();
		
	}

}

輸出結果(部分)

火車站不可能只有一個售票口,所以多加幾個線程

public class ThreadTicketDemo {
	public static void main(String[] args) {
		ThreadTicket tt = new ThreadTicket();
		Thread t1 = new Thread(tt);
		t1.setName("售票口1");
		t1.start();
		
		Thread t2 = new Thread(tt);
		t2.setName("售票口2");
		t2.start();
		
		Thread t3 = new Thread(tt);
		t3.setName("售票口3");
		t3.start();
	}

}

輸出結果(部分)

細心的朋友應該發現最后售票是十分不規律的,例如售票口2已經在售賣最后一張票的時候,售票口3還在售賣第十一張票,其實這是符合生活規律的,大家思考一下自己買票的經歷。因為cpu調用每個線程都是隨機的,而線程的運行也是需要時間的,售票口3在售賣第十一張票的時候,cpu不斷調用售票口2,持續售票。

為了讓程序更明顯一點,我們在程序中加入sleep()

public class ThreadTicket implements Runnable {

	private static int ticketNum = 100;

	@Override
	public void run() {
		while (true) {
			if (ticketNum > 0) {

				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				System.out.println(Thread.currentThread().getName() + ":" + ticketNum--);
			}
		}

	}

	public static int getTicketnum() {
		return ticketNum;
	}

}

再次輸出

首先可以發現程序明顯變慢,然后發現有一些錯誤,第六張票售出兩次,并且沒有票的時候還售出一張,這是因為當票數還是正常的情況下,例如一張,其中一個線程進行判斷,并進入休息。另一個進程也進入判斷。這時兩個進程同時通過判斷,休息后,同時進行了輸出,就會出現這樣的錯誤。

那么如何解決這個問題呢?
synchronized:同步(鎖),可以修飾代碼塊和方法,被修飾的代碼塊和方法一旦被某個線程訪問,則直接鎖住,其他的線程將無法訪問。

方法一:
同步代碼塊:

synchronized(鎖對象){

}

注意:鎖對象需要被所有的線程所共享
方法二:
同步方法:使用關鍵字synchronized修飾的方法,一旦被一個線程訪問, 則整個方法全郁鎖住,其他線程則無法訪問。

注意:
非靜態同步方法的鎖對象是this
靜態的同步方法的鎖對象是當前類的字節碼對象

在這里如果遇到了加鎖后出現了只有一個線程運行的情況,可以參考
synchronized同步方法\塊只有一個線程執行\運行

同步的特點:
同步:安全性高,效率低
非同步:效率高,但是安全性低


原文鏈接:https://www.cnblogs.com/zllk/p/12656722.html
如有疑問請與原作者聯系

標簽:通過解決for時間AVHTTP

版權申明:本站文章部分自網絡,如有侵權,請聯系:west999com@outlook.com
特別注意:本站所有轉載文章言論不代表本站觀點,本站所提供的攝影照片,插畫,設計作品,如需使用,請與原作者聯系,版權歸原作者所有

上一篇:【從零開始學Java筆記】網絡編程

下一篇:【從零開始學Java筆記】Set類和Map類

韩国三级在线看免费