并發與并行
并發:兩個或多個事件(執行緒)在同一時間段內發生(一個Cpu交替執行)
并行:兩個或多個事件(執行緒)在同一時刻發生
執行緒與行程
行程:是指一個記憶體中運行的應用程式,每個行程都有一個獨立的記憶體空間,一個應用程式可以同時運行多個行程;行程也是程式的一次執行程序,是系統運行程式的基本單位;系統運行一個程式即是一個行程從創建、運行到消亡的程序,
進入到記憶體的程式就是行程
執行緒:能獨立運行的基本單位,也是獨立調度和分派的基本單位, 不具備獨立的記憶體空間
行程和執行緒的區別
- 地址空間:行程是資源分配的基本單位,執行緒與資源分配無關,它屬于某個行程,與其它執行緒一起共享此行程的地址空間
- 切換和調度:執行緒背景關系切換比行程背景關系切換要快得多
- 在多執行緒OS中,行程不是一個可執行的物體,
執行緒調度
- 分時調度:所有執行緒輪流使用cpu的使用權,平均分配每個執行緒使用時間
- 搶占式調度:優先讓優先級高的執行緒使用CPU,如果優先級相同,則隨機分配,Java則是搶占式調度
主執行緒:執行main方法的執行緒
main方法執行程序:JVM執行main方法,首先將main方法放入堆疊記憶體中,開辟一條main通向CPU的路
徑,這個路徑就叫做main(主)執行緒,
創建多執行緒
第一種方式:
1、創建一個Thread的子類
2、重寫Thread的run() 方法,run中寫的是新執行緒執行的任務
3、創建一個Thread的子類物件
4、main中呼叫該物件的start方法
第二種方式:
1、創建一個實作類實作Runnable介面,實作類中實作run()方法,設定執行緒任務
2、創建一個實作類物件
3、創建一個thread物件,構造方法中傳遞Runnable實作類物件名稱
4、利用Thread物件呼叫start()方法,開啟新執行緒執行run()方法
(執行緒多次啟動是違法的,執行緒結束執行結束后,不能再重新啟動)
兩種方法的區別(Runnable的優點)
1、Java不允許多繼承,使用Runnable實作后,還可以繼承其它類
2、方便資源共享(共享一個實體物件),將設定執行緒任務和開啟新執行緒進行了分離(解耦),增強了程式的可擴展性,
public class SnapUpThread implements Runnable {
private int ticket = 100;
static int i = 0;
String name = "用戶";
@Override
public void run() { //設定執行緒任務
i++;
int nameNumber = i;
while(true){
if (ticket <= 0) {
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + nameNumber + "搶到票:" + ticket--);
}
}
}
public static void main(String[] args) {
SnapUpThread runnable = new SnapUpThread();
new Thread(runnable).start(); //開啟新執行緒
new Thread(runnable).start(); //開啟新執行緒
}
結果:
多執行緒的原理
當JVM執行main方法時,開辟了一條從main方法通向CPU的路徑(執行緒),當執行到Thread th = new newThread();時,由再開辟一條從th通向CPU的路徑,執行到start()方法時便開始執行th執行緒的run方法,
對于CPU而言,便有了選擇權,隨機選擇執行緒執行,這就有了程式的隨機列印結果,同樣也可以認為,兩個執行緒同時搶奪CPU的執行權(執行時間),
Thread常用方法
- 獲取執行緒名稱兩種方式:通過物件名來獲取執行緒名稱(物件.getName()),或者通過Thread的靜態方法獲取當前執行緒Thread.currentThread().getName()
- 設定執行緒名稱兩種方式:通過物件名來獲取執行緒名稱(物件.setName()),或者在新執行緒中寫一個帶參name構造方法,呼叫父類構造,并傳入name引數
- 暫停:Thread.sleep(xxx毫秒);使當前執行緒暫停xxx秒
執行緒安全問題

解決辦法
在賣票時(操作共享資料),即使失去cpu控制權,也不允許其它執行緒來操作共享資料,
當一個執行緒1搶到cpu使用權后,執行到synchronized陳述句時,獲得了唯一的鎖物件,因此就算失去cpu使用權,別的執行緒因為沒有得到鎖物件,會一直在synchronized陳述句阻塞,直到執行緒1釋放出鎖物件,
1、同步代碼塊實作
synchronized(鎖物件){
//操作共享資料的陳述句
}

注意:
- 鎖物件可以是任意型別物件
- 多個執行緒中的鎖物件必須是同一個
- 靜態方法中的鎖物件比較特殊,是本類的class屬性-->class檔案物件
2、同步方法實作
把操作共享資料的陳述句封裝成一個方法,方法修飾符后增加synchronized
(同步方法的鎖物件其實就是創建的Runnable實作類物件,所以在第一個方法中也可以使用this作為鎖物件傳入)
public synchronized int payTicket(){
if (ticket <= 0) {
return 0;
}
System.out.println(name + nameNumber + "搶到票:" + ticket);
ticket--;
return 1;
}
int a = 1;
while(a == 1){
a = payTicket();
}
3、使用Java.util.concurrent.locks.ReentrantLock
1、創建ReentrantLock rt = new ReentrantLock();
2、在操作共享資料的陳述句前加鎖:rt.lock();
3、在操作完共享資料的陳述句后放掉鎖:rt.unlock();
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/255147.html
標籤:其他

