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