天天看點

多線程學習總結

一、多線程概念

A:程序:程序指正在運作的程式。确切的來說,當一個程式進入記憶體運作,即變成一個進 程,程序是處于運作過程中的程式,并且具有一定獨立功能。

B:線程:線程是程序中的一個執行單元,負責目前程序中程式的執行,一個程序中至少有 一個線程。一個程序中是可以有多個線程的,這個應用程式也可以稱之為多線程程式。

C:簡而言之:一個程式運作後至少有一個程序,一個程序中可以包含多個線程

D:什麼是多線程呢?即就是一個程式中有多個線程在同時執行

二、多線程解析

多 -->多個

線—> 執行線路

程—>程式

多個執行線路的程式,一個程式開啟就會對應一個程序,一個程序中可以有多個執行線程。

三、多線程并發

并行:

同時執行;

并發:

輪流執行;

四、多線程使用

(1)建立線程第一種的步驟
	1.定義一個類繼承Thread
	2. 重寫run方法
	3.将要執行的代碼放入到run方法中
	4.建立子類執行個體
	5.調用start();
	調用run()和start()方法的差別:
		run()方法隻是一個普通的方法
		start()虛拟機會幫我們開啟一條執行線路
	線程的特點:
		從哪裡跌倒就從哪裡爬起來;

(2)建立線程的第二種的步驟
	1.定義一個類去實作runnable接口
	2.實作run方法
	3. 将要執行的寫到run方法中,
	4.建立實作類A的執行個體
	5.建立Thread的執行個體,将A作為構造參數傳遞過來
	6.通過hread的執行個體的執行個體開啟線程;

(3)兩種方式的匿名内部類的方式實作
	
	new Thread(){//定義一個類繼承Thread

		public void run(){//重寫Thread的run方法
			需要執行的代碼;//将需要執行的代碼放入run方法中
		}
	}.start();//開啟線程


	new Thread(new Runnable(){//定義一個類實作Runable

		public void run(){//重寫Thread的run方法
			需要執行的代碼;//将需要執行的代碼放入run方法中
		}
	}).start();//通過Thread開啟線程
           

五、多線程案例

用多線程模拟買火車票案例:需求(用三個線程模拟三個售票視窗,共同賣100張火車票,每個線程列印出賣第幾張票)以下是詳細源代碼:

package com.qx;
/*
 * 1、使用同步代碼塊解決:
 * 
 * 分析問題出現的原因:
 * 		要有多個線程
 * 		要有被多個線程所共享的資料
 * 		多個線程并發的通路共享的資料
 * 
 * synchronized:同步(鎖),可以修飾代碼塊和方法,被修飾的代碼塊和方法一旦被某個線程通路,則直接鎖住,其他的線程将無法通路
 * 
 * 同步代碼塊:
 * 	  synchronized(鎖對象){ }			
 * 
 * 注意:鎖對象需要被所有的線程所共享
 * 	       同步:安全性高,效率低      非同步:效率高,但是安全性低
 * 
 * 
 * 2、使用同步方法解決:
 * 
 * 同步方法:使用關鍵字synchronized修飾的方法,一旦被一個線程通路,則整個方法全部鎖住,其他線程則無法通路
 * 
 * 格式:
 * A:修飾符  synchronized 傳回值 方法名() { }
 * 
 * B:修飾符  static synchronized 傳回值 方法名() { }
 *  
 * 注意:
 * 	 非靜态同步方法的鎖對象是this
 * 	 靜态的同步方法的鎖對象是目前類的位元組碼對象
 * 
 */
public class TicketThread implements Runnable {

	//定義火車票數量
	//int tickets = 100;  //方法一
	static int tickets = 100;  //方法二,需要使用靜态修飾
	
	//建立一個對象
	Object obj = new Object();
	
	//方法一
	/*@Override
	public void run() {
		//出售火車票
		while(true) {
			synchronized (obj) {
				//當火車票小于0張,則停止售票
				if(tickets > 0) {					
					 
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					//鍊式程式設計
					System.out.println(Thread.currentThread().getName() + ":" +tickets--);
				}
			}
		}
	}*/
	
	//方法二
	@Override
	public void run() {
		//出售火車票
		while (true) {			
			//method(); //使用synchronized方法			
			method2(); //使用static synchronized 靜态方法
		}	
	}
	
	private synchronized void method(){
		if(tickets >0 ){ 當火車票小于0張,則停止售票
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//鍊式程式設計
			System.out.println(Thread.currentThread().getName() + ":" +tickets--);
		}
	}
	
	private static synchronized void method2() {	
		if (tickets > 0) { 當火車票小于0張,則停止售票
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//鍊式程式設計
			System.out.println(Thread.currentThread().getName() + ":" + tickets--);
		}
	}
	
}
           

火車買票案例測試代碼

package com.qx;

public class TicketThreadDemo {
	public static void main(String[] args) {
		
		//建立線程對象
		TicketThread tkh = new TicketThread();
		
		//建立三個售票視窗以及顯示售票視窗名稱
		Thread t1 = new Thread(tkh);
		t1.setName("售票視窗1");
		
		Thread t2 = new Thread(tkh);
		t2.setName("售票視窗2");
		
		Thread t3 = new Thread(tkh);
		t3.setName("售票視窗3");
		
		//啟動線程
		t1.start();
		t2.start();
		t3.start();
	}
}
           

六、線程應用場景

A:多線程的常見應用場景:

1、背景任務,例如:定時向大量(100w以上)的使用者發送郵件;

2、異步處理,例如:發微網誌、記錄日志等;

3、分布式計算

B:多線程最多的場景:web伺服器本身;各種專用伺服器(如遊戲伺服器);

七、線程間的通行

注意重點: 線程間的通信是通過同步鎖來通信,注意需要通信的線程的鎖必須一樣吧

wait();//使目前線程處于等待狀态, 這個隻能被notify()或者notifyAll()喚醒

notify();//喚醒這把鎖上除本線程以外的其他任意一條線程;

final的最後一個作用:延長資料的生命周期,把資料存儲到常量池中,JDK1.8後,自動 加final

内部類通路局部變量的時候,局部變量需要被final修飾,延長變量的生命周期

八、線程生命周期

多線程學習總結

九、異常注意事項

A:如果父類方法有異常,子類在重寫這個方法的時候,不能比父類的這個方法抛出的異常大

B:如果父類的方法沒有異常,子類在重寫這個方法的時候,就不能有異常;