多執行緒與高并發
寫下本系列文章,用以記錄學習多執行緒與高并發的程序,
一些比較基礎的知識會直接帶過,不做詳細說明,
執行緒
下面會從介紹執行緒到實作java多執行緒來講,
執行緒的概念
執行緒的概念在我之前寫的《Java開發者需要了解的硬體知識 (二)、作業系統篇》中已經講述過了,搬過來用一用,
行程是OS分配資源的基本單位,執行緒是執行調度的基本單位,
行程最重要的分配資源是:獨立的記憶體空間,
執行緒調度執行(執行緒共享行程的記憶體空間,沒有自己獨立的記憶體空間)

執行緒在Linux中的實作
執行緒在Linux就是一個普通的行程,只不過和其他行程共享資源(記憶體空間,全域資料等,,,)
在JVM中的執行緒
創建一個JVM中執行緒,即申請一個作業系統的執行緒(重量級執行緒),1:1關系
JAVA中的執行緒
創建執行緒的兩種方式
public class createThred {
static class Thread1 extends Thread {
@Override
public void run() {
System.out.println("Thread1");
}
}
static class Runnable1 implements Runnable {
public void run() {
System.out.println("Thread2");
}
}
public static void main(String[] args) {
// 第一種:寫一個類繼承Thread類,重寫它的run方法
Thread1 thread1 = new Thread1();
thread1.start();
// 第二種:寫一個類實作Runnable介面,然后使用新類作為引數來創建新執行緒
Thread thread2 = new Thread(new Runnable1());
thread2.start();
// 第二種的拓展,在Jdk8后使用lambda運算式
Thread thread3 = new Thread(() -> System.out.println("Thread3"));
thread3.start();
}
}
創建執行緒有兩種方式,啟動執行緒上有三種方式,
前兩種就是創建執行緒的那兩種,第三種啟動執行緒的方式是在執行緒池中創建執行緒(使用Executors.newCachedThread,實際上內部還是前兩種來實作的)
執行緒的狀態
JAVA中執行緒的狀態可以主要分成6種
- 新生狀態(NEW):執行緒剛被創建出來,還未呼叫start()方法
- 可運行狀態(RUNNABLE):處于該狀態的執行緒隨時可以被作業系統調度執行,它還可以根據執行緒作業情況細分為①就緒狀態Ready②正在執行狀態Running,
- 阻塞狀態(BLOCKED):執行緒進入同步代碼塊前,需要獲取鎖,而在等待獲取鎖時,執行緒就會進入阻塞狀態,獲得鎖后則進入就緒狀態,
- 等待狀態(WAITING):等待狀態的執行緒都在等待另一個執行緒的特定操作(以解除它的等待狀態),等待狀態結束回到就緒狀態,
- 超時等待狀態(TIMED_WAITING):執行緒在等待另一個執行緒的特定操作后的指定時間內,會處于超時等待狀態,直至操作完成并等待足夠的時間后執行緒會被自動喚醒,并回到就緒狀態
- 終結狀態(TERMINATED):執行緒完成了他的執行方法后即進入終結狀態,而且終結狀態的執行緒無法再start(),
/** * Thread state for a thread which has not yet started. */ NEW, /** * Thread state for a runnable thread. A thread in the runnable * state is executing in the Java virtual machine but it may * be waiting for other resources from the operating system * such as processor. */ RUNNABLE, /** * Thread state for a thread blocked waiting for a monitor lock. * A thread in the blocked state is waiting for a monitor lock * to enter a synchronized block/method or * reenter a synchronized block/method after calling * {@link Object#wait() Object.wait}. */ BLOCKED, /** * Thread state for a waiting thread. * A thread is in the waiting state due to calling one of the * following methods: * <ul> * <li>{@link Object#wait() Object.wait} with no timeout</li> * <li>{@link #join() Thread.join} with no timeout</li> * <li>{@link LockSupport#park() LockSupport.park}</li> * </ul> * * <p>A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called {@code Object.wait()} * on an object is waiting for another thread to call * {@code Object.notify()} or {@code Object.notifyAll()} on * that object. A thread that has called {@code Thread.join()} * is waiting for a specified thread to terminate. */ WAITING, /** * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: * <ul> * <li>{@link #sleep Thread.sleep}</li> * <li>{@link Object#wait(long) Object.wait} with timeout</li> * <li>{@link #join(long) Thread.join} with timeout</li> * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> * </ul> */ TIMED_WAITING, /** * Thread state for a terminated thread. * The thread has completed execution. */ TERMINATED;
執行緒的基本方法
1、sleep(long millis)
? 使執行緒睡眠millis毫秒,執行緒進入時間等待狀態(TIMED_WAITING),睡眠完后執行緒回到就緒狀態,
2、yeild()
? 使當前執行緒進入等待隊列(就緒狀態),等待作業系統下一次調度,
3、join()
? 在T1執行緒中呼叫T2的join()方法時,T1執行緒則會等待T2執行緒結束才進入等待佇列(就緒狀態),(呼叫自己執行緒的join方法是沒有意義的)
4、isAlive()
? 判斷執行緒是否活動,回傳boolean,在呼叫start()后與執行緒死亡前都是活動狀態,
5、getPriority()/setPriority(int newPriority)
? 獲取執行緒優先級與設定執行緒優先級,下圖為執行緒優先級參考表,一般為5,優先級高并不一定會優先執行,只是優先執行的概率更高,

6、interrupt()
>中斷執行緒,**interrupt() 并不能真正的中斷執行緒,這點要謹記,需要被呼叫的執行緒自己進行配合才行,也就是說,一個執行緒如果有被中斷的需求,那么就需要這樣做:**
>
>1. 在正常運行任務時,經常檢查本執行緒的中斷標志位,如果被設定了中斷標志就自行停止執行緒,
>2. 在呼叫阻塞方法時正確處理InterruptedException例外,(例如:catch例外后就結束執行緒,)
圖解執行緒

同步鎖Synchronized
本篇只是簡要說明synchronized關鍵字的一些使用場景和使用細節,
在下一篇中,會詳細的分析synchronized鎖的實作和它的內部原理,
synchronized的鎖定物件
1、指定物件
你可以指定一個物件,使用synchronized關鍵字來加鎖
public class T {
private int count = 10;
private Object o = new Object();
public void m() {
// 你也可以指定this物件
// synchronized (this)
synchronized (o)
{
count--;
}
}
}
2、修飾方法
也可以直接在方法屬性中使用synchronized,如此一來,會默認把呼叫該方法的物件作為鎖(也就是this)
public class T {
private int count = 10;
public synchronized void m() {
// 此時與上面第一種鎖定this物件的效果是一樣的
count--;
}
}
3、修飾靜態方法
使用靜態方法是不需要物件的,如果synchronized修飾靜態方法,那么鎖定的物件將是T.class,類的物件
public class T {
private int count = 10;
public synchronized static void m() {
// 此時與上面第一種鎖定this物件的效果是一樣的
count--;
}
}
可重入性
如果在同一個執行緒中,對于一個物件,允許同步方法A的代碼塊中呼叫同步方法B,(前提是處于一個類中,鎖的是同一個物件)
比如下面這塊代碼
public class T {
synchronized void m1 () {
System.out.println("m1");
m2();
}
synchronized void m2 () {
System.out.println("m1");
}
}
synchronized必須是可重入鎖,因為java中A繼承B,A重寫B的方法時的super.m()是可以正常執行的(無論這個方法是不是加了synchronized),如果不是可重入的,那么這樣的繼承重寫就沒辦法實作,
例外
如果在程式執行中拋出例外,那么鎖會被釋放,可能會因此產生不可預知的結果,
如果不想釋放鎖,可以主動catch產生的例外,
鎖升級
synchronized在JDK早期,使用時會向作業系統申請重量級鎖,在隨后的升級版本中,加入了鎖升級的概念,
意味著,synchronized不再是直接向作業系統申請重量級鎖,而是一步步升級為重量級鎖,
其中的程序有:
1、偏向鎖
? 當沒有任何競爭時(單執行緒執行synchronized代碼時)
2、自旋鎖
? 少量執行緒競爭
3、系統鎖
? 大量執行緒競爭
具體實作
由于synchronized具體實作牽扯到了許多方面的知識,新開一篇文章講,會寫在下一篇里,,,,,,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/70479.html
標籤:Java
