日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[网络开发]同步与线程安全方案

發布時間:2023/12/10 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [网络开发]同步与线程安全方案 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

方案:synchronized,volatile+CAS(compareAndSet),atomic包,Lock接口

java同步和IO同步的對比:

都是同步異步的方案問題,一個操作的是java代碼(實際是堆和方法區),一個操作的是TCP RecvBuffer而已

?

線程安全方案:

https://www.cnblogs.com/jianmianruxin/p/7583262.html
---------------------
原文:https://blog.csdn.net/u010287873/article/details/82387494

?http://blog.csdn.net/yangcheng33/article/details/47708631? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?線程安全實現方案?

線程不安全的原因是:多個線程使用線程共享數據時不能保證更新操作的原子性。

線程安全策略:

一:互斥同步

? ? ? ?這是一種悲觀同步方案,互斥同步要求使用共享資源的線程必須滿足對共享數據的訪問具備原子性。如果該線程沒有完全結束對共享數據的訪問,其他線程不得訪問共享數據。

? ? ? ?互斥同步的實現方式有synchronized和ReentrantLock兩種方式:

前者獲取鎖的過程中獲取不到時線程會被放入隊列陷入阻塞等待。后者可以提供非阻塞獲取鎖的方式,比如trylock和interruptibly。

? ? ? ?synchronized既可以修飾實例方法也可以修飾類方法,也可以作為同步塊。

1.某個線程獲取到對象鎖時,這個對象的所有被synchronized修飾的同步方法將被此線程鎖住,其他線程只能訪問此對象的非synchronized方法。

2.每個對象都有鎖,一個對象被一個線程上鎖,不影響同屬一個類的其他實例對象的鎖狀態,其他線程可以訪問另一個實例對象的非同步方法。

3.synchronized修飾類方法時:同步類方法被執行時所有對象的鎖狀態變為1,所有對象被上鎖。

? ? ? ? ReentrantLock跟synchronized相比還包括了中斷鎖等候和定時鎖等候,當線程A先獲得了對象鎖,線程B在指定時間內無法獲取鎖時可以自動放棄等待該鎖。

ReentrantLock使用代碼實現,系統無法自動釋放鎖,需要在代碼中finally子句中顯式釋放鎖lock.unlock(); Lock lock = new ReentrantLock(); lock.lock(); try{ //可能會出現線程安全的操作 }finally{ //一定在finally中釋放鎖 //也不能把獲取鎖在try中進行,因為有可能在獲取鎖的時候拋出異常 lock.ublock(); } ReentranLock的API:
  • void lock() 獲取鎖,調用該方法當前線程將會獲取鎖,當鎖獲取后,該方法將返回。獲取不到會一直獲取,因此此方法是阻塞的。
  • boolean tryLock() 嘗試非阻塞的獲取鎖,調用該方法立即返回,true表示獲取到鎖
  • boolean tryLock(long time,TimeUnit unit) throws InterruptedException?和tryLock()方法是類似的,只不過區別在于這個方法在拿不到鎖時會等待一定的時間,在時間期限之內如果還拿不到鎖,就返回false
  • void lockInterruptibly() throws InterruptedException 可中斷獲取鎖,與lock()方法不同之處在于該方法會響應中斷,即在鎖的獲取過程中可以中斷當前線程
  • 當一個線程獲取了鎖之后,是不會被interrupt()方法中斷的。interrupt()方法不能中斷正在運行過程中的線程,線程處于阻塞狀態才可被中斷(如線程調用了sleep,join,wait方法等),但線程獲取鎖的過程中不可被中斷(除了上面新學的方法lockInterruptibly)。線程中斷只能。
  • Thread.interrupt()方法不會中斷一個正在運行的線程。它的作用是,在線程受到阻塞時拋出一個中斷信號,這樣線程就得以退出阻塞的狀態。更確切的說,如果線程被Object.wait, Thread.join和Thread.sleep三種方法之一阻塞,那么,它將接收到一個中斷異常(InterruptedException),從而提早地終結被阻塞狀態。

    interrupt方法并不是強制終止線程,它只能設置線程的interrupted狀態,被block的線程(sleep() or join())在被調用interrupt時會產生InterruptException(lock是不會的,直到獲取到鎖才會去處理中斷標志),此時是否終止線程由本線程自己決定

  • 說白了線程的中斷方法的作用并不是中斷線程,而是把已經阻塞的線程的中斷標志改為true(起作用的基本條件是阻塞),但這個標志不一定立即起作用,lockInterruptibly會立即處理該標志,但lock()方法直到獲取到了鎖才會處理中斷標志。
  • void unlock() 釋放鎖
?ReentrantLock是Lock接口一種常見的實現,它是支持重進入的鎖即表示該鎖能夠支持一個線程對資源的重復加鎖。該鎖還支持獲取鎖時的公平與非公平的選擇。?
關于鎖的重進入,其實synchronized關鍵字也支持。如前所述,synchronized關鍵字也是隱式的支持重進入而對于ReentrantLock而言,對于已經獲取到鎖的線程,再次調用lock()方法時依然可以獲取鎖而不被阻塞。

synchronized和ReentrantLock都是可重入鎖,可重入性在我看來實際上表明了鎖的分配機制:基于線程的分配,而不是基于方法調用的分配。舉個簡單的例子,當一個線程執行到某個synchronized方法時,比如說method1,而在method1中會調用另外一個synchronized方法method2,此時線程不必重新去申請鎖,而是可以直接執行方法method2。

  看下面這段代碼就明白了:

1 2 3 4 5 6 7 8 9 class?MyClass { ????public?synchronized?void?method1() { ????????method2(); ????} ????? ????public?synchronized?void?method2() { ????????? ????} }

?  上述代碼中的兩個方法method1和method2都用synchronized修飾了,假如某一時刻,線程A執行到了method1,此時線程A獲取了這個對象的鎖,而由于method2也是synchronized方法,假如synchronized不具備可重入性,此時線程A需要重新申請鎖。但是這就會造成一個問題,因為線程A已經持有了該對象的鎖,而又在申請獲取該對象的鎖,這樣就會線程A一直等待永遠不會獲取到的鎖。

  而由于synchronized和Lock都具備可重入性,所以不會發生上述現象。

剛剛提到的公平獲取鎖與非公平獲取鎖。如果在絕對時間上,先對于鎖進行獲取的請求一定先被滿足,那么這個鎖就是公平的,反之就是非公平的。公平的獲取鎖也就是等待時間最久的線程優先獲取到鎖。ReentrantLock的構造函數來控制是否為公平鎖。

我在第一次了解到公平獲取鎖與非公平獲取鎖的時候,第一反應是公平獲取鎖的效率高,應該使用公平獲取鎖。但實際的情況是,非公平獲取鎖的效率遠遠大于公平獲取鎖。

?

java的線程是映射到操作系統的原生線程之上的,如果要阻塞或喚醒一個線程都需要操作系統來幫忙完成,因此需要從用戶態切換到內核態。對于代碼簡單的同步塊,狀態轉換消耗的時間可能比代碼執行的時間還要長。因此重量級的synchronized除非有必要否則不使用。API中ReentrantLock和synchronized一樣是互斥的方案,一樣是可重入的,但多了一些高級功能如可中斷,公平鎖及鎖可以綁定條件等。

二:非阻塞同步

三:可重入代碼

如果一段代碼的執行結果是可預測的,并且輸入相同的數據會得到相同的數據,那么這段代碼就是可重入代碼,當然也是線程安全的。

?

?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?用戶態與內核態的切換

內核態:?CPU可以訪問內存所有數據, 包括外圍設備, 例如硬盤, 網卡. CPU也可以將自己從一個程序切換到另一個程序

用戶態:?只能受限的訪問內存, 且不允許訪問外圍設備. 占用CPU的能力被剝奪, CPU資源可以被其他程序獲取

為什么要有用戶態和內核態

由于需要限制不同的程序之間的訪問能力, 防止他們獲取別的程序的內存數據, 或者獲取外圍設備的數據, 并發送到網絡, CPU劃分出兩個權限等級 --?用戶態?和?內核態

所有用戶程序都是運行在用戶態的, 但是有時候程序確實需要做一些內核態的事情, 例如從硬盤讀取數據, 或者從鍵盤獲取輸入等. 而唯一可以做這些事情的就是操作系統, 所以此時程序就需要先操作系統請求以程序的名義來執行這些操作.

這時需要一個這樣的機制: 用戶態程序切換到內核態, 但是不能控制在內核態中執行的指令

這種機制叫系統調用, 在CPU中的實現稱之為陷阱指令(Trap Instruction)

他們的工作流程如下:

  • 用戶態程序將一些數據值放在寄存器中, 或者使用參數創建一個堆棧(stack frame), 以此表明需要操作系統提供的服務.
  • 用戶態程序執行陷阱指令
  • CPU切換到內核態, 并跳到位于內存指定位置的指令, 這些指令是操作系統的一部分, 他們具有內存保護, 不可被用戶態程序訪問
  • 這些指令稱之為陷阱(trap)或者系統調用處理器(system call handler). 他們會讀取程序放入內存的數據參數, 并執行程序請求的服務
  • 系統調用完成后, 操作系統會重置CPU為用戶態并返回系統調用的結果
  • 新生的小心情

    ?

    轉載于:https://www.cnblogs.com/PrestonL/p/9938705.html

    總結

    以上是生活随笔為你收集整理的[网络开发]同步与线程安全方案的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。