一.進程與線程
進程
我們在進行操作電腦的時候,通常會打開瀏覽器,通訊工具等應用程序,這個時候CPU通過作業調度在內存中就會分配一些空間讓它們處於宏觀上的運行狀態(處於可以被CPU執行的狀態),而這部分空間資源就可以說是相應的進程占據的,很顯然運行不同的程序需要不同的進程,在內存中也為它們分配獨立,無共享的區域。靜態描述進程的是PCB快(數據結構集),它是系統感知進程存在的唯一實體,通常包含進程名(或者標識符),用戶名(或者用戶標識號),家族關系。
進程的狀態
就緒態:進程獲得了除cpu以外的其他資源,進入搶占cpu的隊列中
執行態:cpu正在執行該進程
阻塞態:進程繼續執行的某個事件條件(如I/O設備)尚未具備
掛起態:處理機調度將進程調離內存進入外存
終止態:進程結束。(當我們撤銷一個進程的時候,會通過PCB結構遞歸刪除所有它的子進程,否者子進程可能處於無法控制的狀態。)
(撤銷進程的流程)
進程阻塞與掛起
阻塞詳細流程圖:
阻塞與掛起的區別:
1.首先阻塞是被動行為,當資源完備后,任然受cpu調度進入就緒狀態,而掛起是主動行為,進程外存后,不受cpu作業調度,通過resume()函數進入就緒態。
2.發生原因不同:阻塞原因是針對這單個進程等待發生的條件不具備,而掛起原因內存資源有限暫時調離內存的過程。
線程
線程也稱為輕型進程。線程的作用域在單個特定的線程內。一個進程內支持多個線程。這些線程的特點是:共享一定的內存區和數據。它們是彼此相互獨立的,可以並發進行,宏觀上看來是同時運行的,但實際上CPU在一個時刻只能處理一個子任務,分時操作系統采用了“時間片的策略”,即CPU將時間切割為時間片,然后將這些時間片分配給這些程序,只有獲得時間片的程序才被執行。還有一個概念叫做主線程,它是進程初始化后自動啟動的線程,如java里面的main。
進程與線程的區別
資源方面:一個進程包含多個線程,同類的多個線程共享一塊內存和數據資源,而進程之間(包括子進程與父進程之間)是完全獨立的,不存在資源的共享。
功能方面:進程是並發程序執行過程中資源分配的基本單元,線程是程序運行與調度的基本單元。
處理機的調度
(圖片來自:http://www.cnblogs.com/dyllove98/p/3249243.html)
cpu調度發生的情況總結:
(1)創建進程:將進程讀入內存中;
(2)進程終止:每當一個進程終止時,必須進行調度;從就緒隊列中選擇要執行的下一個進程;
(3)等待事件:運行進程由於等待I/O、信號量或其他原因不能繼續,這時cpu對I/O設備發出啟動指令,並將當前進程調入等待區;
(4)中斷發生:當I/O設備完成時后會發出I/O中斷,CPU完成中斷響應,之后進行現場保護,中斷服務,中斷返回一系列調度;
(5)運到到時:當進程進程分配的時間片用完,此時選擇新的進程投入運行。
(很明顯掛起的進程不需要cpu進行作業調度)
二.進程的優先級
對於所有線程都具有它自己的優先級,優先級高的首先被CPU執行,當某個線程處於運行狀態時,那些尚未擁有優先級的處於可運行狀態的線程會自動獲得優先級。還存在另一種情況,當某個線程在運行時,一個更高優先級的線程處於可運行狀態,這是這個線程被立即執行,這稱為先占式調度。
三.線程的開發方法
1.實現Runnable接口實現它的run()方法
2.繼承Thread類,覆蓋它的run()方法----Thread已經實現了Runnable接口實現了run方法,因此繼承Thread的類是覆蓋run()方法
(Runnable實現線程解決了java單一繼承的局限性)
Thread/Runnable原理請看本人另一博客http://www.cnblogs.com/kundeg/p/6576094.html
四.線程池
背景:例如web服務器,數據庫服務器,文件服務器等服務器端應用程序,都面臨這來着客戶端的請求,這些請求的整體特點是:單個任務處理的時間很短,但是請求的數目巨大
瓶頸:對於在進程內划分線程已經是個很大的改進,但仍然存在以下問題,對於每個到達服務器端的請求,單獨為它們創建一個線程,將請求處理完后,再將線程銷毀,然后線程創建與銷毀的時間比處理請求的時間要多得多。同時線程過多,也會消耗內存。
改進:初始的時候便創建一個線程池(擁有i個線程),當請求到達時便擁有線程池中的某個線程(免去了創建時間),當線程池中的所有線程都被占據的時候,其他請求需要等待,占據線程的請求處理完后,線程又空余出來,新的請求可以進入。此處會有一定的等待時間,但和原來繁瑣的線程創建和銷毀相比,性能改進不少,同時線程池的構建也需要不斷優化。
五.線程的狀態以及運行控制
線程的運行狀態
上述表明了線程在運行過程中的5種狀態:
初始化狀態:通過new實例化了一個線程對象,但該對象是空的並沒有分配資源
可運行狀態:通過start()方法,為該線程分配了除了CPU外的所需資源(進入隊列,排隊等待CPU),處於Runnable狀態
運行狀態:線程調度控制CPU處理一個Runnable線程,這個時候才實際上執行run()函數的代碼
阻塞狀態:正在運行的線程由於某些事件尚未具備(例如:輸入輸出)從而進入進入阻塞狀態,來到阻塞池等待
掛起狀態: A,通過調用sleep()方法使線程進入休眠狀態,線程在指定時間內不會運行。
B,通過調用join()方法使線程掛起,如果某個線程在另一個線程t上調用t.join(),這個線程將被掛起,直到線程t執行完畢為止。
C,通過調用wait()方法使線程掛起,直到線程得到了notify()和notifyAll()消息,線程才會進入“可執行”狀態。
(區別進程的掛起,線程不擁有資源,也不存在將資源放入外存中)
死亡狀態:線程結束了(Dead),可由這些原因導致:1.該線程運行完畢。2.意外退出。3.父類線程控制其消亡。
線程的運行控制
1.線程的啟動start()
public class test extends Thread{ public void run(){ while(true){ System.out.println("子線程運行中---"); } } } public static void main(String args[]){ test t =new test(); t.start(); try{ Thread.sleep(2000);//父線程進入等待池等待
} catch(Exception e ){ } t.stop(); }//在上述實例中,通過main主線程創建了一個子線程,他們是相互獨立,並發執行,但是父線程可以控制子線程的狀態,例如stop()
2.休眠(sleep)與掛起(yield),join
相同:休眠與掛起都會使線程暫停處於等待狀態
區別:休眠可以設定時間,並且期間任何優先級的線程都可以由可運行狀態變為可執行狀態,而掛起不可以設定時間,只有同等優先級的線程可以變成可執行狀態
join立即執行方法
class test1 extends Thread{ static int count = 0; public void run(){ for(int i=0;i<5;i++){ count++; } } } public class join { public static void main(String ats[]){ test1 t = new test1() ; try { t.start(); t.join();//如果沒有這條語句輸出為0,當前輸出為5
} catch (InterruptedException e) { // TODO Auto-generated catch block
e.printStackTrace(); } System.out.println(test1.count); } }
3.synchronized()
1.當兩個並發線程訪問同一個對象中的這個synchronized(this)同步代碼塊時,首先訪問的線程獲得對象鎖,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊
public class synchronized1 implements Runnable { public void run() { synchronized(this) { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " 執行" ); } } } public static void main(String[] args) { synchronized1 t1 = new synchronized1(); Thread ta = new Thread(t1, "A"); Thread tb = new Thread(t1, "B"); ta.start(); tb.start(); } } //結果
B執行 B執行 B執行 B執行 B執行 A執行 A執行 A執行 A執行 A執行
2.當一個線程訪問一個類對象的一個synchronized(this)同步代碼塊時,獲得對象鎖,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。
public class synchoronized2 { public void syn() { synchronized(this) { for(int i=0;i<5;i++){{ System.out.println(Thread.currentThread().getName() + "執行ing"); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } } } public void notSyn() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() +"執行ing"); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } public static void main(String[] args) { synchoronized2 s2 = new synchoronized2(); Thread t1 = new Thread(new Runnable() { public void run() { s2.syn(); } }, "t1"); Thread t2 = new Thread(new Runnable() { public void run() { s2.notSyn(); } }, "t2"); t1.start(); t2.start(); } } //結果 t2執行ing t1執行ing t2執行ing t1執行ing t1執行ing t2執行ing t2執行ing t1執行ing t1執行ing t2執行ing
3.當一個線程訪問一個對象的一個synchronized(this)同步代碼塊時,獲得對象鎖,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞
public class synchronized3 { public void syn1() { synchronized (this) { for(int i=0;i<5;i++) { System.out.println(Thread.currentThread().getName() + "執行ing"); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } } public void syn2() { //synchronized修飾方法,結果一樣
synchronized (this) { for(int i=0;i<5;i++) { System.out.println(Thread.currentThread().getName() + "執行ing"); try { Thread.sleep(500); } catch (InterruptedException ie) { } } } } public static void main(String[] args) { synchronized3 s = new synchronized3(); Thread t1 = new Thread(new Runnable() { public void run() { s.syn1(); } }, "t1"); Thread t2 = new Thread(new Runnable() { public void run() { s.syn2(); } }, "t2"); t1.start(); t2.start(); } } //結果
t1執行ing t1執行ing t1執行ing t1執行ing t1執行ing t2執行ing t2執行ing t2執行ing t2執行ing t2執行ing
4.區別對象鎖和類鎖:對象鎖和類鎖互不干擾,一個線程可以同時具有對象鎖和類鎖
public class synchronized4 { public static instancet i = new instancet(); public static instancet getI() { return i; } public static void main(String args[]) { Thread t1 = new Thread(new tt(), "t1"); Thread t2 = new Thread(new tt(), "t2"); Thread t3 = new Thread(new tt(), "t3"); Thread t4 = new Thread(new tt(), "t4"); t1.start(); t2.start(); t3.start(); t4.start(); } } class tt implements Runnable { public void run() { if (Thread.currentThread().getName().equals("t1")) { synchronized4.getI().getClassLock(Thread.currentThread().getName()); } else if (Thread.currentThread().getName().equals("t2")) { synchronized4.getI().getObjectLock(Thread.currentThread().getName()); } else if (Thread.currentThread().getName().equals("t3")) { synchronized4.getI().getClassLock(Thread.currentThread().getName()); } else { synchronized4.getI().getObjectLock(Thread.currentThread().getName()); } } } class instancet { public synchronized void getObjectLock(String s) { System.out.println(s + "獲得對象鎖"); try { Thread.sleep(2000);//線程進入休眠,但仍然具有對象鎖 } catch (Exception e) { } } public synchronized static void getClassLock(String s) { System.out.println(s + "獲得類鎖"); try { Thread.sleep(4000); } catch (Exception e) { } } } //結果
t2獲得對象鎖 t1獲得類鎖 t4獲得對象鎖 t3獲得類鎖
4.sleep(time),經過一段時間后自動喚醒,sleep后線程進入不可執行狀態,但仍然具有鎖,對其他線程有阻塞作用
上述代碼已經說明sleep的作用
5.wait()與notify(),wait()線程進入休眠且放棄鎖
public class synchronized7 { public static void main(String[] args) { new Thread(new Thread1()).start(); try { Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } new Thread(new Thread2()).start(); } private static class Thread1 implements Runnable{ @Override public void run(){ synchronized (synchronized7.class) { System.out.println("線程1正在執行ing"); try {System.out.println("線程1進入休眠"); synchronized7.class.wait();//休眠且放棄鎖
} catch (Exception e) { e.printStackTrace(); } System.out.println("線程1繼續執行"); System.out.println("線程1結束"); } } } private static class Thread2 implements Runnable{ @Override public void run(){ synchronized (synchronized7.class) { System.out.println("線程2正在執行ing"); synchronized7.class.notify(); try { Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } System.out.println("線程2繼續執行"); System.out.println("線程2結束"); } } } } //結果
線程1正在執行ing 線程1進入休眠 線程2正在執行ing 線程2繼續執行 線程2結束 線程1繼續執行 線程1結束
6.wait()與sleep()區別
public class waitandsleep extends Thread{ static int number = 10; public void firstMethod() throws Exception { synchronized (this) { number += 100; System.out.println(number); } } //下面是否加上static,又是一種同步鎖,結果不一樣
public synchronized void secondMethod() throws Exception { /**用於區別wait和sleep *1.sleep(在Thread的靜態方法)的時候仍然占有機鎖,釋放cpu
*2.wait(Object的方法)的時候釋放機鎖,其他線程塊可以進入,釋放cpu
**/
//Thread.sleep(2000);//輸出2100
this.wait(2000);//輸出110
number *= 200; } public void run() { try { firstMethod(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { waitandsleep ws=new waitandsleep(); ws.start(); ws.secondMethod();
ps:純手打,圖片是拍的書上的,勉強看的清楚,感覺自己寫博文一直有個弊端,試圖在一篇文章里面囊括一個大的知識工廠,但現在發現能將一個點講清楚就非常非常困難,所以這篇失敗的博文,還將繼續改善,fighting!!
更新+1+1+1