JUC前置知識
JUC概述
在開發語言中,執行緒部分是重點,JUC是關於執行緒的。JUC是java.util.concurrent工具包的簡稱。這是一個處理執行緒的工具包,JDK1.5開始出現的。
執行緒和程序
執行緒和程序的概念
程序(process): 是計算機的程式關於某資料集合上的一次允許活動,是作業系統進行資源分配和任務排程的最小單位,是作業系統的基礎。在當代面向執行緒設計的計算機結構中,程序是執行緒的容器。程式是指令,資料及其組織形式的描述,程序是程式的實體。
執行緒(thread): 是作業系統或CPU核心能夠進行排程的最小單位。被包含在程序中,是程序中的實際執行單位。一條執行緒指的是程序中一個單一順序的控制流,一個程序中可以有多個執行緒,每個執行緒執行不同的任務。
總結
程序,是在系統中正在執行的一個應用程式,程式一旦執行就是程序,也是作業系統資源分配的最小單位。
執行緒,是CPU(Central Processing Unit縮寫)核心(現代計算機的CPU可以有多個CPU核心,俗稱的4核,8核等)進行資源排程的最小單位,或者說程序內獨立執行的一個執行流單元,也是程式執行的最小單位。
執行緒的狀態
執行緒狀態類
public enum State {
/**
* 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 <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* 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;
}
wait和sleep方法的區別
1.sleep是Thread類的靜態方法,wait是Object類的方法,任何物件例項都能呼叫。
2.sleep不會釋放鎖,也不需要佔有鎖。wait會釋放鎖,但釋放鎖這個動作的前提是,當前執行緒佔有鎖。
3.這兩個方法都可以被interrupted方法中斷。
4.這兩個方法還有個特點,就是執行緒在哪裡被阻塞,就在哪裡被喚醒。
序列,並行和併發
序列模式
序列表示所有任務一一按先後順序進行。序列意味著必須先裝完一車柴才能運送這車柴,只有運送到了,才能卸下這車柴,並且只有完成了這三個步驟,才能進行下一步驟。序列是一次只能取得一個任務,並執行這個任務。
並行模式
並行意味著可以同時取得多個任務,,並同時去執行所取得的這些任務。並行模式相當於將長長的一條佇列,劃分成了多條短佇列,所以並行縮短了任務佇列的長度。並行的效率從程式碼層次上,強依賴於多程序/多執行緒程式碼,從硬體角度上依賴於多核CPU。
併發
指的是多個程式可以同時執行的現象,更細化的是多程序可以同時執行或者多指令可以同時執行。
併發的重點是一種現象,描述的是多程序同時執行的現象。但實際上,一個CPU同時,只能執行一個執行緒。所以同時執行,不是同一時刻有多個執行緒執行的現象,而是提供一種功能,讓使用者看起來多個程式同時執行了,但是實際上的執行緒不是一直霸佔CPU的,而是執行一會停,一會執行。
要解決大併發問題,通常是將大任務分解成多個小任務,由於OS(Operating System)對程序的排程是隨機的,所以切分成多個小任務後,可能會從任一小任務出執行。可能出現的問題,一個小任務執行了多次,還沒開始下個任務。這時一般會採用佇列或類似資料結構來存放各個小任務的成果。可能出現還沒準備好第一步,就執行第二步的可能。這時,一般採用多路複用或非同步的方式,比如只有準備好了,才產生事件執行下一步任務。可以多程序/多執行緒的方式並行執行這些小任務。也可以單程序/單執行緒執行這些小任務,這是很可能要配合多路複用才能達到較高的效率。
小結
併發:同一時刻多個執行緒在訪問同一資源,多個執行緒對一個點。如春運搶票,電商秒殺。
並行:多項工作一起執行,之後再彙總。如泡泡麵,水壺燒水,一邊放調料。
管程
管程又叫Monitor(監視器),在OS中叫管程/Monitor(監視器),在Java中叫鎖(Lock)。
鎖其實是一種同步機制,保證同一時間內,只能有一個執行緒訪問受保護的資源。
在JVM中實現這個鎖機制(同步機制),是透過進入,退出管程物件實現的,也就是常說的持有鎖,和釋放鎖。進入管程(擁有鎖),退出管程(釋放鎖)。一個執行緒持有該鎖,就只有當前執行緒可以訪問,該鎖保護的資源。釋放鎖,就是當前執行緒不訪問,該鎖保護的資源了,其他執行緒可以競爭該鎖,誰獲取到鎖,可以訪問鎖保護的執行緒。
使用者執行緒和守護執行緒
daemon n.守護神
使用者執行緒和守護執行緒,是jvm中的概念。
使用者執行緒,顧名思義,使用者自定義的執行緒。主執行緒結束,使用者執行緒還在執行,jvm存活。
守護執行緒 ,用於守護使用者執行緒,執行的執行緒如垃圾回收(gc)。沒有使用者執行緒,都是守護執行緒的話,主執行緒結束,jvm結束。設定一個執行緒為守護執行緒,必須在開啟這個執行緒之前。
//程式碼效果參考:http://www.mwgw.cn/sitemap/post.xml
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().isDaemon());// aa true
while(true){
}
},"aa");
thread.setDaemon(true);//透過該方法可將執行緒設定為守護執行緒
thread.start();
System.out.println(Thread.currentThread().getName() + "over");// mainover
}