單線程-多線程-高併發

什麼是進程?
當一個程序開始運行時,它就是一個進程,進程包括運行中的程序和程序所使用到的內存和系統資源。
而一個進程又是由多個線程所組成的。


什麼是線程?
線程是程序中的一個執行流,每個線程都有自己的專有寄存器(棧指針、程序計數器等),但代碼區是共享的,
即不同的線程可以執行同樣的函數。

什麼是高併發,及高併發的處理 ?

之前我將高併發的解決方法誤認爲是線程或者是隊列可以解決,因爲高併發的時候是有很多用戶在訪問,導致出現系統數據不正確、丟失數據現象,所以想到 的是用隊列解決,其實隊列解決的方式也可以處理,比如我們在競拍商品、轉發評論微博或者是秒殺商品等,同一時間訪問量特別大,隊列在此起到特別的作用,將 所有請求放入隊列,以毫秒計時單位,有序的進行,從而不會出現數據丟失系統數據不正確的情況。

今天我經過查資料,高併發的解決方法有倆種,一種是使用緩存、另一種是使用生成靜態頁面;還有就是從最基礎的地方優化我們寫代碼減少不必要的資源浪費:(

1.不要頻繁的new對象,對於在整個應用中只需要存在一個實例的類使用單例模式.對於String的連接操作,使用StringBuffer或者StringBuilder.對於utility類型的類通過靜態方法來訪問。

2. 避免使用錯誤的方式,如Exception可以控制方法推出,但是Exception要保留stacktrace消耗性能,除非必要不要使用 instanceof做條件判斷,儘量使用比的條件判斷方式.使用JAVA中效率高的類,比如ArrayList比Vector性能好。)

首先緩存技術我一直沒有使用過,我覺得應該是在用戶請求時將數據保存在緩存中,下次請求時會檢測緩存中是否有數據存在,防止多次請求服務器,導致服務器性能降低,嚴重導致服務器崩潰,這只是我自己的理解,詳細的資料還是需要在網上收集;

什麼是多線程?
多線程是指程序中包含多個執行流,即在一個程序中可以同時運行多個不同的線程來執行不同的任務,
也就是說允許單個程序創建多個並行執行的線程來完成各自的任務。


多線程的好處:
可以提高CPU的利用率。在多線程程序中,一個線程必須等待的時候,CPU可以運行其它的線程而不是等待,
這樣就大大提高了程序的效率。 


多線程的不利方面:
線程也是程序,所以線程需要佔用內存,線程越多佔用內存也越多; 
多線程需要協調和管理,所以需要CPU時間跟蹤線程; 
線程之間對共享資源的訪問會相互影響,必須解決競用共享資源的問題;
線程太多會導致控制太複雜,最終可能造成很多Bug;

 多線程的幾種實現方式
(1) 繼承Thread類創建線程

Thread類本質上是實現了Runnable接口的一個實例,代表一個線程的實例。啓動線程的唯一方法就是通過Thread類的start()實例方法。start()方法將啓動一個新線程,並執行run()方法。這種方式實現多線程比較簡單,通過自己的類直接繼承Thread,並重寫run()方法,就可以啓動新線程並執行自己定義的run()方法。
(2) 實現Runnable接口創建線程

如果自己的類已經繼承了兩一個類,就無法再繼承Thread,因此可以實現一個Runnable接口
(3) 實現Callable接口通過FutureTask包裝器來創建Thread線程

(4) 使用ExecutorService、Callable、Future實現有返回結果的線程

哪些集合類是線程安全的

  • 1.Vector
  • 2.Stack
  • 3.hashtable
  • 4.enumeration
  • 5.StringBuffer

線程與進程
進程是一個實體。每一個進程都有它自己的地址空間,一般情況下,包括文本區域(text region)、數據區域(data region)和堆棧(stack region)。文本區域存儲處理器執行的代碼;數據區域存儲變量和進程執行期間使用的動態分配的內存;堆棧區域存儲着活動過程調用的指令和本地變量。
一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程自己不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。
區別不同 
a,地址空間:進程內的一個執行單元;進程至少有一個線程;它們共享進程的地址空間;而進程有自己獨立的地址空間; 
b,資源擁有:進程是資源分配和擁有的單位,同一個進程內的線程共享進程的資 
c,線程是處理器調度的基本單位,但進程不是. 
d,二者均可併發執行.

java thread狀態
NEW 狀態是指線程剛創建, 尚未啓動
RUNNABLE 狀態是線程正在正常運行中, 當然可能會有某種耗時計算/IO等待的操作/CPU時間片切換等, 這個狀態下發生的等待一般是其他系統資源, 而不是鎖, Sleep等
BLOCKED 這個狀態下, 是在多個線程有同步操作的場景, 比如正在等待另一個線程的synchronized 塊的執行釋放, 也就是這裏是線程在等待進入臨界區
WAITING 這個狀態下是指線程擁有了某個鎖之後, 調用了他的wait方法, 等待其他線程/鎖擁有者調用 notify / notifyAll 一遍該線程可以繼續下一步操作, 這裏要區分 BLOCKED 和 WATING 的區別, 一個是在臨界點外面等待進入, 一個是在理解點裏面wait等待別人notify, 線程調用了join方法 join了另外的線程的時候, 也會進入WAITING狀態, 等待被他join的線程執行結束
TIMED_WAITING 這個狀態就是有限的(時間限制)的WAITING, 一般出現在調用wait(long), join(long)等情況下, 另外一個線程sleep後, 也會進入TIMED_WAITING狀態
TERMINATED 這個狀態下表示 該線程的run方法已經執行完畢了, 基本上就等於死亡了(當時如果線程被持久持有, 可能不會被回收)
 

wait()和sleep()的區別
sleep來自Thread類,和wait來自Object類
調用sleep()方法的過程中,線程不會釋放對象鎖。而 調用 wait 方法線程會釋放對象鎖
sleep睡眠後不出讓系統資源,wait讓出系統資源其他線程可以佔用CPU
sleep(milliseconds)需要指定一個睡眠時間,時間一到會自動喚醒
 

ExecutorService、Callable、Future三個接口實際上都是屬於Executor框架。返回結果的線程是在JDK1.5中引入的新特徵,有了這種特徵就不需要再爲了得到返回值而大費周折了。
可返回值的任務必須實現Callable接口;無返回值的任務必須實現Runnabel接口。
執行Callable任務後,可以獲取一個Future對象,在該對象上調用get()方法就可以獲取到Callable任務返回的Object了。(get()方法是阻塞的,線程無返回結果,該方法就一直等待)
 

多線程與單線程的區別
生活舉例
你早上上班,正要打卡的時候,手機響了。。你如果先接了電話,等接完了,在打卡,就是單線程。
如果你一手接電話,一手打卡。就是多線程。
2件事的結果是一樣的。。你接了電話且打了卡。

多線程處理的優點

同步應用程序的開發比較容易,但由於需要在上一個任務完成後才能開始新的任務,所以其效率通常比多線程應用程序低。如果完成同步任務所用的時間比預計時間長,應用程序可能會不響應。多線程處理可以同時運行多個過程。例如,文字處理器應用程序在您處理文檔的同時,可以檢查拼寫(作爲單獨的任務)。由於多線程應用程序將程序劃分成獨立的任務,因此可以在以下方面顯著提高性能: 
多線程技術使程序的響應速度更快,因爲用戶界面可以在進行其他工作的同時一直處於活動狀態。 
當前沒有進行處理的任務可以將處理器時間讓給其他任務。 
佔用大量處理時間的任務可以定期將處理器時間讓給其他任務。 
可以隨時停止任務。 
可以分別設置各個任務的優先級以優化性能。 

是否需要創建多線程應用程序取決於多個因素。在以下情況下,最適合採用多線程處理:
耗時或大量佔用處理器的任務阻塞用戶界面操作。 
各個任務必須等待外部資源(如遠程文件或 INTERNET 連接)。 

例如,用於跟蹤 WEB 頁上的鏈接並下載滿足特定條件的文件的 INTERNET 應用程序“ROBOT”。這種應用程序可以依次同步下載各個文件,也可以使用多線程同時下載多個文件。多線程方法比同步方法的效率高很多,因爲即使在某些線程中遠程 WEB 服務器的響應非常慢,也可以下載文件。

下面是多線程的例子
還在DOS時代,人們就在尋求一種多任務的實現。於是出現了TSR類型的後臺駐留程序,比較有代表性的有SIDE KICK、VSAFE等優秀的TSR程序,這類程序的出現和應用確實給用戶使用計算機帶來了極大的方便,比如SIDE KICK,們編程可以在不用進編輯程序的狀態下,一邊編輯源程序,一邊編譯運行,非常方便。但是,DOS單任務操作系統的致命缺陷註定了在DOS下不可能開發出真正的多任務程序。進入WINDOWS3.1時代,這種情況依然沒有根本的改變,一次應用只能做一件事。比如數據庫查詢,除非應用編得很好,在查詢期間整個系統將不響應用戶的輸入。
 進入了WINDOWS NT和WINDOWS 9X時代,情況就有了徹底的改觀,操作系統從真正意義上實現了多任務(嚴格地說,WIN9X還算不上)。一個應用程序,在需要的時候可以有許多個執行線程,每個線程就是一個小的執行程序,操作系統自動使各個線程共享CPU資源,確保任一線程都不能使系統死鎖。這樣,在編程的時候,可以把費時間的任務移到後臺,在前臺用另一個線程接受用戶的輸入。對那些對實時性要求比較高的編程任務,如網絡客戶服務、串行通信等應用時,多線程的實現無疑大大地增強了程序的可用性和穩固性。

----------------------------------------------------------------------------------------------------------------------------------

1。單進程單線程:一個人在一個桌子上吃菜。
2。單進程多線程:多個人在同一個桌子上一起吃菜。
3。多進程單線程:多個人每個人在自己的桌子上吃菜。

多線程的問題是多個人同時吃一道菜的時候容易發生爭搶,例如兩個人同時夾一個菜,一個人剛伸出筷子,結果伸到的時候已經被夾走菜了。。。此時就必須等一個人夾一口之後,在還給另外一個人夾菜,也就是說資源共享就會發生衝突爭搶。


1。對於 Windows 系統來說,【開桌子】的開銷很大,因此 Windows 鼓勵大家在一個桌子上吃菜。因此 Windows 多線程學習重點是要大量面對資源爭搶與同步方面的問題。


2。對於 Linux 系統來說,【開桌子】的開銷很小,因此 Linux 鼓勵大家儘量每個人都開自己的桌子吃菜。這帶來新的問題是:坐在兩張不同的桌子上,說話不方便。因此,Linux 下的學習重點大家要學習進程間通訊的方法。

--
補充:有人對這個開桌子的開銷很有興趣。我把這個問題推廣說開一下。

開桌子的意思是指創建進程。開銷這裏主要指的是時間開銷。
可以做個實驗:創建一個進程,在進程中往內存寫若干數據,然後讀出該數據,然後退出。此過程重複 1000 次,相當於創建/銷燬進程 1000 次。在我機器上的測試結果是: 
UbuntuLinux:耗時 0.8 秒 
Windows7:耗時 79.8 秒 
兩者開銷大約相差一百倍。

這意味着,在 Windows 中,進程創建的開銷不容忽視。換句話說就是,Windows 編程中不建議你創建進程,如果你的程序架構需要大量創建進程,那麼最好是切換到 Linux 系統。

大量創建進程的典型例子有兩個,一個是 gnu autotools 工具鏈,用於編譯很多開源代碼的,他們在 Windows 下編譯速度會很慢,因此軟件開發人員最好是避免使用 Windows。另一個是服務器,某些服務器框架依靠大量創建進程來幹活,甚至是對每個用戶請求就創建一個進程,這些服務器在 Windows 下運行的效率就會很差。這"可能"也是放眼全世界範圍,Linux 服務器遠遠多於 Windows 服務器的原因。

--
再次補充:如果你是寫服務器端應用的,其實在現在的網絡服務模型下,開桌子的開銷是可以忽略不計的,因爲現在一般流行的是按照 CPU 核心數量開進程或者線程,開完之後在數量上一直保持,進程與線程內部使用協程或者異步通信來處理多個併發連接,因而開進程與開線程的開銷可以忽略了。

另外一種新的開銷被提上日程:核心切換開銷。

現代的體系,一般 CPU 會有多個核心,而多個核心可以同時運行多個不同的線程或者進程。

當每個 CPU 核心運行一個進程的時候,由於每個進程的資源都獨立,所以 CPU 核心之間切換的時候無需考慮上下文。

當每個 CPU 核心運行一個線程的時候,由於每個線程需要共享資源,所以這些資源必須從 CPU 的一個核心被複制到另外一個核心,才能繼續運算,這佔用了額外的開銷。換句話說,在 CPU 爲多核的情況下,多線程在性能上不如多進程。

因而,當前面向多核的服務器端編程中,需要習慣多進程而非多線程。
----------------------------------------------------------------------------------------------------------------------------------
很多人答案說的是操作系統提供的多進程而不是單個程序內的多線程。

多線程使得程序內部可以分出多個線程來做多件事情,而不會造成程序界面卡死。比如迅雷等多線程下載工具就是典型的多線程。一個下載任務進來,迅雷把文件平分成10份,然後開10個線程分別下載。這時主界面是一個單獨的線程,並不會因爲下載文件而卡死。而且主線程可以控制下屬線程,比如某個線程下載緩慢甚至停止,主線程可以把它強行關掉並重啓另外一個線程。

另外就是一些程序的打印功能,比如記事本、Adobe Reader,打印的時候就只能打印,無法在主界面進行操作,而Word就有“後臺打印”的功能,點了打印命令之後,還可以回到主界面進行修改、保存等操作。

另外多線程除了並行完成一些任務以外,還有生產者-消費者模式。比如Windows命令行下在某個硬盤根目錄執行一個"dir/s | more"命令,前一條顯示硬盤裏的所有文件,要執行很久才能執行得完,後面那條命令會把前面命令的輸出分屏顯示出來。但是執行整條命令時,會立刻有顯示,也就是說,前面一條命令輸出滿一頁內容到緩衝區,more命令就把緩衝區封死了,等用戶敲了一個鍵顯示下一屏的時候,more命令把緩衝區的內容取出並清空,前面的命令才能輸出下一屏到緩衝區。這樣的多線程使得整條命令不用等待前面的命令全部執行完才能執行下一條命令。

多線程和多進程的區別。平常指的多進程是操作系統下同時運行多個進程,比如Word和Excel同時打開,並且可以並行地同時執行一些操作。這種多進程和多線程沒什麼好比較的。可以比較的是同一個程序裏的多線程和多進程。

多線程因爲在同一個進程裏,所以可以共享內存和其他資源,比如迅雷裏10個線程一齊下載一個文件,這個文件是由進程打開的,然後10個線程都可以往裏寫入東西。如果是10個進程就不行了,操作系統不允許一個文件由兩個進程同時寫入。另外,Chrome就是一個典型的多進程程序,裏面每個標籤頁、擴展、插件都是單獨的進程,各自獨佔資源,相互隔離,一個進程出錯死掉只會影響一個頁面或者插件,再也不會出現Flash插件出錯崩潰導致整個瀏覽器崩潰的情況了。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章