內存,線程問題


項目中關於內存,本地緩存,redis緩存,分級緩存的問題

緩存

緩存從百度中查找可知就是數據交換的緩沖區(稱作Cache),當某一硬件要讀取數據時,會首先從緩存中查找需要的數據,如果找到了則直接執行,找不到的話則從內存中找。由於緩存的運行速度比內存快得多,故緩存的作用就是幫助硬件更快地運行。通常人們所說的Cache就是指緩存SRAM。 SRAM叫靜態內存,“靜態”指的是當我們將一筆數據寫入SRAM后,除非重新寫入新數據或關閉電源,否則寫入的數據保持不變。
分級緩存就是類似於計算機系統中內存分類為1.主存儲器和大容量磁盤,2.高速緩存Cache,3.cpu內部寄存器。按1,2,3順序容量逐漸減小,但是訪問速度是越來越快。
分級緩存就是項目中為了提高請求的訪問速度,分類為local cache->redis cache->date base.
其中第一層cache容量小於第二層cache,訪問速度大於第二層。分級方法以此類推。第一層cache的更新速度比較快,第二層更新數據庫時間比較長。
當有請問時,會先訪問local cache,如果數據有,則返回,如果沒有,就從下一層cache取數據,存儲到該層中,返回。
redis cache層是一樣的。
緩存定期清空,然后再循環新一輪存儲數據。

緩存一致性

多處理器系統只有一個待運行的線程隊列,內存中也只有一個操作系統拷貝,而且也只有一個內存系統,但是會有多個cpu同時運行不同的線程。一個cpu運行一個線程,那么上圖中的系統最多能在同一時間運行2個線程。其實,多處理系統需要掌握的知識不是這些,而是緩存一致性。
現在來解釋下什么是緩存一致性。由於,還是只有一個內存系統。所有cpu都要和這個內存系統通信,但是只有一條總線,那么這無疑會造成總線緊張,限制整體的速度了。那么,你多個cpu也沒多少意義了。解決這個問題的辦法還是利用cpu的緩存機制,學過組成原理的同學都知道,cpu的緩存命中率還是很高的,有90%以上吧。那么,我繼續利用緩存機制還是可以降低總線的頻繁使用的。但是,每個cpu都有自己的緩存。如果有2個cpu的緩存存儲的是同一內存數據的內容,其中一個cpu的緩存更新了,另外一個cpu的緩存也必須更新,這就是所謂的緩存一致性。編程多線程程序的一個很重要的一點就是避免因為緩存一致性引起的緩存更新風暴。

多線程及一些關鍵字

如果使用多線程,那么就必須考慮線程同步,而線程同步又是導致速度降低的關鍵。所以下面就講述一些方法來加快多線程程序的吞吐速度。
方法一,把一個任務分解為多個可以子任務。
因為總有些子任務是可以並發的,多個子任務並發執行了很可能就能夠避免cpu需要io操作的完成了,而且能夠提高系統的吞吐量。
方法二,緩存多線程的共享數據。
當你已經在使用多線程了,很多時候必須使用共享數據。如果,數據是只讀的,那么可以在第一次獲取后保存起來,以后就可以重復使用了。但是,第一次的獲取還是無法避免的需要線程同步操作的。
方法三,如果線程數目有限,就不要共享數據。
做法是為每一個線程實例化一個單獨的數據,其實就是為每一個線程分配一塊數據使用。這樣沒有線程同步操作了,速度可以盡可能的提示。
方法四,如果沒辦法確定線程數目到底有多少,那么使用部分共享吧。
部分共享其實就是使用多個資源池代替一個資源池,資源池的數目得更加經驗來確定。

關於多線程程序

其中運用兩個關鍵字 原子性 AtomicIntegervolatile 同步讀寫。
AtomicInteger保證++操作不會被別的線程打斷,因為該語句的實現時用到多條匯編語言,執行該語句時,可能會被別的線程打斷,沒有出現正確的計算結果。實現該程序塊,要么全部執行,要么全部不執行,不會被從中間打斷。
這是由硬件提供原子操作指令實現的。在非激烈競爭的情況下,開銷更小,速度更快。Java.util.concurrent中實現的原子操作類包括:AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。它保證不實現加鎖,也能實現線程安全。(其實現用到了volatile關鍵字)
volatile 同步讀寫,它是被設計用來修飾被不同線程訪問和修改的變量。
使用地方:
一般說來,volatile用在如下的幾個地方:
1、中斷服務程序中修改的供其它程序檢測的變量需要加volatile;
2、多任務環境下各任務間共享的標志應該加volatile;
3、存儲器映射的硬件寄存器通常也要加volatile說明,因為每次對它的讀寫都可能有不同意義;
另外,以上這幾種情況經常還要同時考慮數據的完整性(相互關聯的幾個標志讀了一半被打斷了重寫),在1中可以通過關中斷來實現,2 中可以禁止任務調度,3中則只能依靠硬件的良好設計了。
還有一個關鍵詞 synchronized.
1、synchronized關鍵字的作用域有二種:
1)是某個對象實例內,synchronized aMethod(){}可以防止多個線程同時訪問這個對象的synchronized方法(如果一個對象有多個synchronized方法,只要一個線程訪問了其中的一個synchronized方法,其它線程不能同時訪問這個對象中任何一個synchronized方法)。這時,不同的對象實例的synchronized方法是不相干擾的。也就是說,其它線程照樣可以同時訪問相同類的另一個對象實例中的synchronized方法;
2)是某個類的范圍,synchronized static aStaticMethod{}防止多個線程同時訪問這個類中的synchronized static 方法。它可以對類的所有對象實例起作用。

2、除了方法前用synchronized關鍵字,synchronized關鍵字還可以用於方法中的某個區塊中,表示只對這個區塊的資源實行互斥訪問。用法是: synchronized(this){/區塊/},它的作用域是當前對象;

3、synchronized關鍵字是不能繼承的,也就是說,基類的方法synchronized f(){} 在繼承類中並不自動是synchronized f(){},而是變成了f(){}。繼承類需要你顯式的指定它的某個方法為synchronized方法;

Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。

 一、當兩個並發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊。

二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。

三、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

四、第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。

五、以上規則對其它對象鎖同樣適用

參見該文了解synchronized關鍵字

一般項目中會有一個主線程,然后還有一些子線程,用戶發來的請求,還在其余線程里。

關於多線程另一個問題參照多線程同步

初始化定時更新任務時,主線程當項目啟動時初始化過程中會同步調用一次,更新一下緩存,副線程會定期周期(前一次執行結束到下一次執行開始的間隔時間(間隔執行延遲時間))更新緩存,初始化延遲時間會分配隨機不同的時間,防止調度多線程時擁擠。
scheduleWithFixedDelay從字面意義上可以理解為就是以固定延遲(時間)來執行線程任務,它實際上是不管線程任務的執行時間的,每次都要把任務執行完成后再延遲固定時間后再執行下一次。

此文是作為小白的我,剛剛接觸到多線程項目時,記錄師兄教的內容的流水賬,可能會有很多錯誤,以后會慢慢改正:-D


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com