java多线程并发控制_Java多线程与并发控制
三、線程的幾種狀態
在Java當中,線程通常都有五種狀態,創建、就緒、運行、阻塞和死亡。
第一是創建狀態。在生成線程對象,并沒有調用該對象的start方法,這是線程處于創建狀態。
第二是就緒狀態。當調用了線程對象的start方法之后,該線程就進入了就緒狀態,但是此時線程調度程序還沒有把該線程設置為當前線程,此時處于就緒狀態。在線程運行之后,從等待或者睡眠中回來之后,也會處于就緒狀態。
第三是運行狀態。線程調度程序將處于就緒狀態的線程設置為當前線程,此時線程就進入了運行狀態,開始運行run函數當中的代碼。
第四是阻塞狀態。線程正在運行的時候,被暫停,通常是為了等待某個時間的發生(比如說某項資源就緒)之后再繼續運行。sleep,suspend,wait(兩者的區別是是否釋放鎖)等方法都可以導致線程阻塞。
第五是死亡狀態。如果一個線程的run方法執行結束或者調用stop方法后,該線程就會死亡。對于已經死亡的線程,無法再使用start方法令其進入就緒
synchronized關鍵字使用說明
synchronized只能標記非抽象的方法,不能標識成員變量。
要同步靜態方法,需要一個用于整個類對象的鎖,這個對象是就是這個類(XXX.class)。
例如:
public static synchronized int setName(String name){
Xxx.name = name;
}
等價于
public static int setName(String name){
synchronized(Xxx.class){
Xxx.name = name;
}
}
1、鎖的原理
Java中每個對象都有一個內置鎖
當程序運行到非靜態的synchronized同步方法上時,自動獲得與正在執行代碼類的當前實例(this實例)有關的鎖。獲得一個對象的鎖也稱為獲取鎖、鎖定對象、在對象上鎖定或在對象上同步。
當程序運行到synchronized同步方法或代碼塊時才該對象鎖才起作用。
一個對象只有一個鎖。所以,如果一個線程獲得該鎖,就沒有其他線程可以獲得鎖,直到第一個線程釋放(或返回)鎖。這也意味著任何其他線程都不能進入該對象上的synchronized方法或代碼塊,直到該鎖被釋放。
釋放鎖是指持鎖線程退出了synchronized同步方法或代碼塊。
關于鎖和同步,有一下幾個要點:
1)、只能同步方法,而不能同步變量和類;
2)、每個對象只有一個鎖;當提到同步時,應該清楚在什么上同步?也就是說,在哪個對象上同步?
3)、不必同步類中所有的方法,類可以同時擁有同步和非同步方法。
4)、如果兩個線程要執行一個類中的synchronized方法,并且兩個線程使用相同的實例來調用方法,那么一次只能有一個線程能夠執行方法,另一個需要等待,直到鎖被釋放。也就是說:如果一個線程在對象上獲得一個鎖,就沒有任何其他線程可以進入(該對象的)類中的任何一個同步方法。
5)、如果線程擁有同步和非同步方法,則非同步方法可以被多個線程自由訪問而不受鎖的限制。
6)、線程睡眠時,它所持的任何鎖都不會釋放。
7)、線程可以獲得多個鎖。比如,在一個對象的同步方法里面調用另外一個對象的同步方法,則獲取了兩個對象的同步鎖。
8)、同步損害并發性,應該盡可能縮小同步范圍。同步不但可以同步整個方法,還可以同步方法中一部分代碼塊。
9)、在使用同步代碼塊時候,應該指定在哪個對象上同步,也就是說要獲取哪個對象的鎖。例如:
public int fix(int y) {
synchronized (this) {
x = x - y;
}
return x;
}
當然,同步方法也可以改寫為非同步方法,但功能完全一樣的,例如:
public synchronized int getX() {
return x++;
}
與
public int getX() {
synchronized (this) {
return x;
}
}
效果是完全一樣的。
在具體的Java代碼中需要完成一下兩個操作:
把競爭訪問的資源類Foo變量x標識為private;
同步哪些修改變量的代碼,使用synchronized關鍵字同步方法或代碼。
JAVA的多線程是搶占式(preemptive)的,意思是調度機制會為每個線程提供時間片,并且通過強制中斷來轉換到下一個線程。搶占式的實現方式對線程的個數有一個限制。與其相對的是協作式(cooperative)的,協作式的多任務系統對任務的數量是沒有限制的,因為任務是自動讓出資源的,并且上下文的轉換成本較小。
線程中斷(Interruption):
線程有以下幾種狀態:初始態(New), 可運行(Runnable), 阻塞(Blocked), 終止(Dead)。線程被創建的即刻為初始態,系統為線程分配必要的資源,所有的資源就位后,萬事具備,只欠東風,此刻進入可運行狀態,調度器可隨時使線程運行或繼續等待(Blocked);
處于阻塞狀態的線程不能獲得CPU 時間,以下事件可以使一個線程進入阻塞狀態:
a) 調用了sleep() 方法(jion()方法等同)
b) 調用了wait() 方法
c) 等待同步鎖,比如進入synchronized 方法
d) 等待 I/O
所謂中斷是指CPU終止當前運行的任務,使其讓出資源讓其他任務操作。java多線程中通常情況下所說的中斷,就是從線程的run() 方法跳出來. 當然最直接的方法就是等待 run()方法執行完畢自動退出。但是多數情況下我們的線程都是長任務線程,比如守護線程(伺服線程),需要長時間不間斷運行。一種可選方法是通過控制變量(這個控制變量,通常是全局變量,以便程序在任何時候任何地點都可以訪問到,并且對控制變量的操作應當是同步的,在java中我們可以選擇使用volatile 變量)。
總結
以上是生活随笔為你收集整理的java多线程并发控制_Java多线程与并发控制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Docker和containerd的优缺
- 下一篇: RabbitMQ——使用Shovel插件