您好,登錄后才能下訂單哦!
這篇文章主要講解了“Java線程之間的共享與協作是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Java線程之間的共享與協作是什么”吧!
進程是操作系統進行資源分配的最小單位,其中包括:CPU、內存空間、磁盤IO 等、同一進程中的多條線程共享該進程中的全部系統資源,而進程和進程直接是相互獨立的。進程是具有一定獨立功能的程序關于某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。
進程是程序在計算機上的一次執行活動。當你運行一個程序,你就啟動了一個進程。顯然程序是死的、靜態的、進程是活動的、動態的。進程可以分為系統進程和用戶進程。凡是用于完成操作系統的各種功能的進程就是系統進程,它們是處于運行狀態下的操作系統本身,用戶進程就是所有由你啟動的進程。
線程是進程的一個實體,是CPU調度和分派的基本單位,它是比經常更小的、能夠獨立運行的基本單位。線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和堆棧),但是它可以與同一個進程的其他線程共享進程所擁有的全部資源。
任何一個程序都必須創建線程,特別是Java不管任何程序都必須啟動一個main函數的主線程;Java web開發的定時任務、定時器、JSP和Servlet、異步消息處理機制,遠程訪問接口 RM 等,任何一個監聽事件,onClick的觸發事件等都離不開線程和并發的知識。
多核心:也指單芯片多處理器(Chip Multiprocessors,簡稱 CMP),CMP是由美國斯坦福大學提出的,其思想是將大規模并行處理器中的SMP(對稱處理器)集成到同一芯片內,各個處理器并行執行不同的進程。這種依靠多個CPU同時并行的運行程序是實現超高速計算的一個重要方向,稱為并行處理。
多線程:Simultaneous Multithreading.簡稱 SMT.讓同一個處理器上的多個線程同步執行并共享處理器的執行資源。
核心數、線程數:目前主流CPU都是多核的。增加核心數目的就是為了增加線程數,因為操作系統是通過線程來執行任務的,一般情況下它們是1:1對應關系,也就是說四核 CPU一般擁有四個線程。但Intel引入超線程技術后,使核心數與線程數形成了1:2的關系。
我們平時在開發的時候,感覺并沒有受CPU 核心數的限制,想啟動線程就啟動線程,哪怕是在單核CPU 上,為什么?這是因為操作系統提供了一種CPU 時間片輪轉機制。
時間片輪轉調度是一種最古老、最簡單、最公平且使用最廣的一種算法,又稱RR 調度。每個進程被分配一個時間段,稱作它的時間片,即該進程運行運行的時間。
我們舉個例子,如果有條高速公路A,上面有4條車道,那么最大并行車輛就是4輛,這條高速公路同時并排行走的車輛小與等于4的時候,車輛就可以并行行駛。CPU也是這個原理,一個CPU相當于一條高速公路,核心數或線程數就相當于并排可以通行的車輛;而多個CPU就相當于有多條高速公路,而每個高速公路并排有多個車道。
當談論并發的時候,一定要加個單位時間,也就是說單位時間內并發量是多少?離開單位時間其實是沒有意義的。
俗話說一心不能二用,這對計算機也一樣,原則上一個CPU只能分配給一個進程,以便運行這個進程。我們通常用的計算機只有一個CPU,也就是說只有一顆心,要讓它一心多用同時運行多個進程,就必須使用并發技術。實現并發技術相當復雜,最容易理解的是“時間片輪轉進程調度算法”。
并發:
指應用能夠交替執行不同的任務,比如單CPU核心下執行多線程并非是同時執行多個任何,如果你開兩個線程執行,就是在你幾乎不可察覺的速度不斷去切換執行這兩個任務,以達到“同時執行”效果,只是計算機的執行速度太快,我們無法察覺到而已。
并行:指應用能夠同時執行不同的任務,例:吃飯的時候可以邊吃飯邊看電視,這兩件事可以同時執行。
**并發和并行兩者的區別就是:一個是交替執行,一個是同時執行**
由于多核CPU的誕生,多線程、高并發的編程越來越受重視和關注。
從上面CPU的介紹,可以看出現在市面上沒有CPU的內核不使用多線程并發機制的,特別是服務器還不止一個CPU。程序的基本調度單元是線程,一個線程也只能在一個一個CPU 的一個核的一個線程跑,如果你是個i3的CPU的話,最差也是雙核心4線程的運算能力:如果是一個線程的話,那就會浪費釣3/4的CPU性能:如果設計一個多線程的話,那它就可以同時在多個CPU 的多個核的多個線程上跑,可以充分的利用CPU,減少CPU的空閑時間,發揮它的運算能力,提高并發量。
比如我們經常使用的下載功能,很多朋友都會開通某一個會員,因為會員版本啟用了多個線程去下載,誰都無法忍受一個線程去下,為什么呢?因為多線程下載快啊。
我們做程序開發的時候,網頁速度提升1s,如果用戶量大的話,就能增加不少轉換量。我們經常瀏覽的網頁中,瀏覽器在加載頁面的時候,都會去多開幾個線程去加載網絡資源,提升網站的相應速度。多線程和高并發,在計算機中,無處不在。
例如我們做一個電商項目,下訂單和給用戶發送短信、郵件就可以進行拆分,將給用戶發送短信、郵件這兩個步驟獨立成兩個單獨的模塊,交給其他線程去執行。這樣即增加了異步的操作,提示了系統性能,又使程序模塊化,清晰化和簡單化。
在同一個進程里面的多線程是資源共享的,也就是都可以訪問同一個內存地址當中的一個變量。
例如:若每個線程中對全局變量、靜態變量只讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程同時執行寫操作,一般都需要考慮線程同步,否則就可能影響線程安全。
為了解決線程之間的安全性引入了Java 鎖的機制,而一不小心就會產生Java 線程死鎖的多線程問題,因為不同的線程都在等待哪些根本不可能被釋放的鎖,從而導致所有的工作都無法完成。
假設有兩個饑餓的人,他們必須共享刀叉并輪流吃飯,他們都需要獲得兩個鎖,共享刀和共享叉。假如線程A獲得了刀,而線程B獲得了叉。線程A就會進入阻塞狀態來等待獲得叉,而線程B則主帥來等待線程A所擁有的刀。這只是人為設計的例子,單盡管在運行時很難探測到,這類情況卻時常發生。
線程數太多有可能造成系統創建大量線程,而導致消耗完系統內存以及CPU的“過渡切換”,造成系統的死機,那么我們改如果解決這類問題呢?
某些系統資源是有限的,如文件描述。多線程程序可能耗盡資源,因為每個線程都可能希望有一個這樣的資源。如果線程數相當大,或者某個資源的侯選線 程數遠遠超過了可用的資源數則最好使用資源池。一個最好的示例是數據庫連接池。只要線程需要使用一個數據庫連接,它就從池中取出一個,使用以后再將它返回池中。資源池也稱為資源庫。
多線程應用開發的注意事項很多,希望大家在日后的工作中可以慢慢體會它 的危險所在。
線程之間相互配合,完成某項工作,比如:一個線程修改了一個對象的值, 而另一個線程感知到了變化,然后進行相應的操作,整個過程開始于一個線程, 而最終執行又是另一個線程。前者是生產者,后者就是消費者,這種模式隔離了 “做什么”(what)和“怎么做”(How),簡單的辦法是讓消費者線程不斷地 循環檢查變量是否符合預期在 while 循環中設置不滿足的條件,如果條件滿足則 退出 while 循環,從而完成消費者的工作。
卻存在如下問題:
難以確保及時性。
難以降低開銷。如果降低睡眠的時間,比如休眠 1 毫秒,這樣消費者能 更加迅速地發現條件變化,但是卻可能消耗更多的處理器資源,造成了無端的浪費。
等待/通知機制:是指一個線程 A 調用了對象 O 的 wait()方法進入等待狀態,而另一個線程 B 調用了對象 O 的 notify()或者 notifyAll()方法,線程 A 收到通知后從對象 O 的 wait() 方法返回,進而執行后續操作。上述兩個線程通過對象 O 來完成交互,而對象 上的 wait()和 notify/notifyAll()的關系就如同開關信號一樣,用來完成等待方和通 知方之間的交互工作。
notify():通知一個在對象上等待的線程,使其從 wait 方法返回,而返回的前提是該線程獲取到了對象的鎖,沒有獲得鎖的線程重新進入 WAITING 狀態。
notifyAll():通知所有等待在該對象上的線程
wait():調用該方法的線程進入 WAITING 狀態,只有等待另外線程的通知或被中斷 才會返回.需要注意,調用 wait()方法后,會釋放對象的鎖。
wait(long):超時等待一段時間,這里的參數時間是毫秒,也就是等待長達n 毫秒,如果沒有 通知就超時返回。
wait (long,int):對于超時時間更細粒度的控制,可以達到納秒
等待和通知的標準范式 等待方遵循如下原則。
獲取對象的鎖。
如果條件不滿足,那么調用對象的 wait()方法,被通知后仍要檢查條件。
條件滿足則執行對應的邏輯。
通知方遵循如下原則:
獲得對象的鎖。
改變條件。
通知所有等待在對象上的線程。
在調用 wait()、notify()系列方法之前,線程必須要獲得該對象的對象級別鎖,即只能在同步方法或同步塊中調用 wait()方法、notify()系列方法,進 入 wait()方法后,當前線程釋放鎖,在從 wait()返回前,線程與其他線程競 爭重新獲得鎖,執行 notify()系列方法的線程退出調用了 notifyAll 的 synchronized 代碼塊的時候后,他們就會去競爭。如果其中一個線程獲得了該對象鎖,它就會 繼續往下執行,在它退出 synchronized 代碼塊,釋放鎖后,其他的已經被喚醒的 線程將會繼續競爭獲取該鎖,一直進行下去,直到所有被喚醒的線程都執行完畢。
notify 和 notifyAll 應該用誰
盡可能用 notifyAll(),謹慎使用 notify(),因為 notify()只會喚醒一個線程,我們無法確保被喚醒的這個線程一定就是我們需要喚醒的線程。
感謝各位的閱讀,以上就是“Java線程之間的共享與協作是什么”的內容了,經過本文的學習后,相信大家對Java線程之間的共享與協作是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。