中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

滁州做網站電話號碼/seo推廣服務哪家好

滁州做網站電話號碼,seo推廣服務哪家好,蘇州房產網,網頁設計基礎知識總結文章目錄并發(fā)編程的三大特性1、原子性什么是并發(fā)編程的原子性?保證并發(fā)編程的原子性synchronizedCASLock鎖ThreadLocal2、可見性什么是可見性?解決可見性的方式volatilesynchronizedLockfinal3、有序性什么是有序性?as-if-serialhappens-beforevolatile并發(fā)編程的…

文章目錄

  • 并發(fā)編程的三大特性
  • 1、原子性
    • 什么是并發(fā)編程的原子性?
    • 保證并發(fā)編程的原子性
      • synchronized
      • CAS
      • Lock鎖
      • ThreadLocal
  • 2、可見性
    • 什么是可見性?
    • 解決可見性的方式
      • volatile
      • synchronized
      • Lock
      • final
  • 3、有序性
      • 什么是有序性?
      • as-if-serial
      • happens-before
      • volatile

并發(fā)編程的三大特性

原子性、可見性、有序性。

1、原子性

什么是并發(fā)編程的原子性?

JMM(Java Memory Model)。不同的硬件和不同的操作系統(tǒng)在內存上的操作有一定差異的。 Java為了解決相同代碼在不同操作系統(tǒng)上出現(xiàn)的各種問題,用JMM屏蔽掉各種硬件和操作系統(tǒng)帶來的差異。
讓Java的并發(fā)編程可以做到跨平臺。 JMM規(guī)定所有變量都會存儲在主內存中,在操作的時候,需要從主內存中復制一份到線程內存(CPU內存),在線程內部做計算。然后再寫回主內存中(不一定)。
原子性的定義:原子性指一個操作是不可分割的,不可中斷的,一個線程在執(zhí)行時,另一個線程不會影響到他。
并發(fā)編程的原子性用代碼闡述:

    private static int count;public static void increment() {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}count++;}public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 100; i++) {increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 100; i++) {increment();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}

當前程序:多線程操作共享數據時,預期的結果,與最終的結果不符。
原子性:多線程操作臨界資源,預期的結果與最終結果一致。
通過對這個程序的分析,可以查看出,++的操作,一共分為了三部,首先是線程從主內存拿到數據,保存到CPU的寄存器中,然后在寄存器中進行+1操作,最終將結果寫回到主內存當中。

保證并發(fā)編程的原子性

synchronized

因為++操作可以從指令中查看到
i++操作可以在方法上追加synchronized關鍵字或者采用同步代碼塊的形式來保證原子性。
synchronized可以讓避免多線程同時操作臨街資源,同一時間點,只會有一個線程正在操作臨界資源。
在這里插入圖片描述

CAS

compare and swap也就是比較和交換,他是一條CPU的并發(fā)原語。
他在替換內存的某個位置的值時,首先查看內存中的值與預期值是否一致,如果一致,執(zhí)行替換操作。這個操作是一個原子性操作。
Java中基于Unsafe的類提供了對CAS的操作的方法,JVM會幫助我們將方法實現(xiàn)CAS匯編指令。 但是要清楚CAS只是比較和交換,在獲取原值的這個操作上,需要你自己實現(xiàn)。

    private static AtomicInteger count = new AtomicInteger(0);public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 100; i++) {count.incrementAndGet();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 100; i++) {count.incrementAndGet();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}

Doug Lea在CAS的基礎上幫助我們實現(xiàn)了一些原子類,其中就包括現(xiàn)在看到的AtomicInteger,還有其他很多原子類。
CAS的缺點:CAS只能保證對一個變量的操作是原子性的,無法實現(xiàn)對多行代碼實現(xiàn)原子性。

CAS帶來的問題

  • ABA問題:問題如下,可以引入版本號的方式,來解決ABA的問題。Java中提供了一個類在CAS時,針對各個版本追加版本號的操作。 AtomicStampeReference在CAS時,不但會判斷原值,還會比較版本信息。
        public static void main(String[] args) {AtomicStampedReference<String> reference = new AtomicStampedReference<>("AAA", 1);String oldValue = reference.getReference();int oldVersion = reference.getStamp();boolean b = reference.compareAndSet(oldValue, "B", oldVersion, oldVersion + 1);System.out.println("修改1版本的:" + b);boolean c = reference.compareAndSet("B", "C", 1, 1 + 1);System.out.println("修改2版本的:" + c);}
    
  • 自旋時間過長問題
    • 可以指定CAS一共循環(huán)多少次,如果超過這個次數,直接失敗/或者掛起線程。(自旋鎖、 自適應自旋鎖)
    • 可以在CAS一次失敗后,將這個操作暫存起來,后面需要獲取結果時,將暫存的操作全部執(zhí)行,再返回最后的結果。

ABA問題:在這里插入圖片描述

  • 線程1從內存位置V中取出A
  • 線程2從內存位置V中取出A
  • 線程2進行了寫操作,將B寫入內存位置V
  • 線程2將A再次寫入內存位置V
  • 線程1進行CAS操作,發(fā)現(xiàn)V中仍然是A,交換成功
    盡管線程1的CAS操作成功,但線程1并不知道內存位置V的數據發(fā)生過改變。

Lock鎖

Lock鎖是在JDK1.5由Doug Lea研發(fā)的,他的性能相比synchronized在JDK1.5的時期,性能好了很很多,但是在JDK1.6對synchronized優(yōu)化之后,性能相差不大,但是如果涉及并發(fā)比較多時,推薦ReentrantLock鎖,性能會更好。

	private static int count;private static ReentrantLock lock = new ReentrantLock();public static void increment() {lock.lock();try {count++;try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}} finally {lock.unlock();}}public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 100; i++) {increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 100; i++) {increment();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}

ReentrantLock可以直接對比synchronized,在功能上來說,都是鎖。但是ReentrantLock的功能性相比synchronized更豐富。
ReentrantLock底層是基于AQS實現(xiàn)的,有一個基于CAS維護的state變量來實現(xiàn)鎖的操作。

ThreadLocal

Java中的四種引用類型分別是強軟弱虛。
User user = new User();
在 Java 中最常見的就是強引用,把一個對象賦給一個引用變量,這個引用變量就是一個強引用。當一個對象被強引用變量引用時,它始終處于可達狀態(tài),它是不可能被垃圾回收機制回收的,即使該對象以后永遠都不會被用到JVM也不會回收。因此強引用是造成 Java 內存泄漏的主要原因之一。
SoftReference
其次是軟引用,對于只有軟引用的對象來說,當系統(tǒng)內存足夠時它不會被回收,當系統(tǒng)內存空間不足時它會被回收。軟引用通常用在對內存敏感的程序中,作為緩存使用。
然后是弱引用,它比軟引用的生存期更短,對于只有弱引用的對象來說,只要垃圾回收機制一運行,不管 JVM 的內存空間是否足夠,總會回收該對象占用的內存??梢越鉀Q內存泄漏問題,ThreadLocal就是基于弱引用解決內存泄漏的問題。
最后是虛引用,它不能單獨使用,必須和引用隊列聯(lián)合使用。虛引用的主要作用是跟蹤對象被垃圾回收的狀態(tài)。不過在開發(fā)中,我們用的更多的還是強引用。

ThreadLocal保證原子性的方式,是不讓多線程去操作臨界資源,讓每個線程去操作屬于自己的數據。

    static ThreadLocal tl1 = new ThreadLocal();static ThreadLocal tl2 = new ThreadLocal();public static void main(String[] args) {tl1.set("123");tl2.set("456");Thread t1 = new Thread(() -> {System.out.println("t1:" + tl1.get());System.out.println("t1:" + tl2.get());});t1.start();System.out.println("main:" + tl1.get());System.out.println("main:" + tl2.get());}

ThreadLocal實現(xiàn)原理:

  • 每個Thread中都存儲著一個成員變量,ThreadLocalMap。
  • ThreadLocal本身不存儲數據,像是一個工具類,基于ThreadLocal去操作ThreadLocalMap。
  • ThreadLocalMap本身就是基于Entry[]實現(xiàn)的,因為一個線程可以綁定多個ThreadLocal,這樣一來,可能需要存儲多個數據,所以采用Entry[]的形式實現(xiàn)。
  • 每一個現(xiàn)有都自己獨立的ThreadLocalMap,再基于ThreadLocal對象本身作為key,對value進行存取ThreadLocalMap的key是一個弱引用,弱引用的特點是,即便有弱引用,在GC時,也必須被回收。這里是為了在ThreadLocal對象失去引用后,如果key的引用是強引用,會導致 ThreadLocal對象無法被回收。

ThreadLocal內存泄漏問題:

  • 如果ThreadLocal引用丟失,key因為弱引用會被GC回收掉,如果同時線程還沒有被回收,就會導致內存泄漏,內* * 存中的value無法被回收,同時也無法被獲取到。
    只需要在使用完畢ThreadLocal對象之后,及時的調用remove方法,移除Entry即可。
    ThreadLocal

2、可見性

什么是可見性?

可見性問題是基于CPU位置出現(xiàn)的,CPU處理速度非???#xff0c;相對CPU來說,去主內存獲取數據這個 事情太慢了,CPU就提供了L1,L2,L3的三級緩存,每次去主內存拿完數據后,就會存儲到CPU的 三級緩存,每次去三級緩存拿數據,效率肯定會提升。

這就帶來了問題,現(xiàn)在CPU都是多核,每個線程的工作內存(CPU三級緩存)都是獨立的,會告知每個線程中做修改時,只改自己的工作內存,沒有及時的同步到主內存,導致數據不一致問題。
MESI
可見性問題的代碼邏輯:

    private static boolean flag = true;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (flag) {// ....}System.out.println("t1線程結束");});t1.start();Thread.sleep(10);flag = false;System.out.println("主線程將flag改為false");}

解決可見性的方式

volatile

volatile是一個關鍵字,用來修飾成員變量。

如果屬性被volatile修飾,相當于會告訴CPU,對當前屬性的操作,不允許使用CPU的緩存,必須去 和主內存操作。

volatile的內存語義:

  • volatile屬性被寫:當寫一個volatile變量,JMM會將當前線程對應的CPU緩存及時的刷新到主內存中。
  • volatile屬性被讀:當讀一個volatile變量,JMM會將對應的CPU緩存中的內存設置為無效,必須去主內存中重新讀取共享變量。

其實加了volatile就是告知CPU,對當前屬性的讀寫操作,不允許使用CPU緩存,加了volatile修飾的 屬性,會在轉為匯編之后,追加一個lock的前綴,CPU執(zhí)行這個指令時,如果帶有l(wèi)ock前綴會做兩個事情:

  • 將當前處理器緩存行的數據寫回到主內存。
  • 這個寫回的數據,在其他的CPU內核的緩存中,直接無效。
    總結:volatile就是讓CPU每次操作這個數據時,必須立即同步到主內存,以及從主內存讀取數據。
    private volatile static boolean flag = true;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (flag) {// ....}System.out.println("t1線程結束");});t1.start();Thread.sleep(10);flag = false;System.out.println("主線程將flag改為false");}

synchronized

synchronized也是可以解決可見性問題的,synchronized的內存語義。
如果涉及到了synchronized的同步代碼塊或者是同步方法,獲取鎖資源之后,將內部涉及到的變量從CPU緩存中移除,必須去主內存中重新拿數據,而且在釋放鎖之后,會立即將CPU緩存中的數據同步到主內存。

    private static boolean flag = true;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (flag) {synchronized (MiTest.class) {//...}System.out.println(111);}System.out.println("t1線程結束");});t1.start();Thread.sleep(10);flag = false;System.out.println("主線程將flag改為false");}

Lock

Lock鎖保證可見性的方式和synchronized完全不同,synchronized基于他的內存語義,在獲取鎖和釋放鎖時,對CPU緩存做一個同步到主內存的操作。
Lock鎖是基于volatile實現(xiàn)的。Lock鎖內部再進行加鎖和釋放鎖時,會對一個由volatile修飾的state屬性進行加減操作。
如果對volatile修飾的屬性進行寫操作,CPU會執(zhí)行帶有l(wèi)ock前綴的指令,CPU會將修改的數據,從 CPU緩存立即同步到主內存,同時也會將其他的屬性也立即同步到主內存中。還會將其他CPU緩存 行中的這個數據設置為無效,必須重新從主內存中拉取。

    private static boolean flag = true;private static Lock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (flag) {lock.lock();try {//...} finally {lock.unlock();}}System.out.println("t1線程結束");});t1.start();Thread.sleep(10);flag = false;System.out.println("主線程將flag改為false");}

final

final修飾的屬性,在運行期間是不允許修改的,這樣一來,就間接的保證了可見性,所有多線程讀 取final屬性,值肯定是一樣。
final并不是說每次取數據從主內存讀取,他沒有這個必要,而且final和volatile是不允許同時修飾一個屬性的。
final修飾的內容已經不允許再次被寫了,而volatile是保證每次讀寫數據去主內存讀取,并且volatile 會影響一定的性能,就不需要同時修飾。
在這里插入圖片描述

3、有序性

什么是有序性?

在Java中,.java文件中的內容會被編譯,在執(zhí)行前需要再次轉為CPU可以識別的指令,CPU在執(zhí)行 這些指令時,為了提升執(zhí)行效率,在不影響最終結果的前提下(滿足一些要求),會對指令進行重排。
指令亂序執(zhí)行的原因,是為了盡可能的發(fā)揮CPU的性能。
Java中的程序是亂序執(zhí)行的。

    static int a, b, x, y;public static void main(String[] args) throws InterruptedException {for (int i = 0; i < Integer.MAX_VALUE; i++) {a = 0;b = 0;x = 0;y = 0;Thread t1 = new Thread(() -> {a = 1;x = b;});Thread t2 = new Thread(() -> {b = 1;y = a;});t1.start();t2.start();t1.join();t2.join();if (x == 0 && y == 0) {System.out.println("第" + i + "次,x = " + x + ",y = " + y);}}}

單例模式由于指令重排序可能會出現(xiàn)問題:
線程可能會拿到沒有初始化的對象,導致在使用時,可能由于內部屬性為默認值,導致出現(xiàn)一些不必
要的問題。

    private static volatile MiTest test;private MiTest() {}public static MiTest getInstance() { // Bif (test == null) {synchronized (MiTest.class) {if (test == null) {// A , 開辟空間,test指向地址,初始化test = new MiTest();}}}return test;}

as-if-serial

as-if-serial語義: 不論指定如何重排序,需要保證單線程的程序執(zhí)行結果是不變的。 而且如果存在依賴的關系,那么也不可以做指令重排。

// 這種情況肯定不能做指令重排序 int i = 0;
i++;
// 這種情況肯定不能做指令重排序 int j = 200;
j * 100;
j + 100;
// 這里即便出現(xiàn)了指令重排,也不可以影響最終的結果,20100

happens-before

具體規(guī)則:

  1. 單線程happen-before原則:在同一個線程中,書寫在前面的操作happen-before后面的操作。
  2. 鎖的happen-before原則:同一個鎖的unlock操作happen-before此鎖的lock操作。
  3. volatile的happen-before原則:對一個volatile變量的寫操作happen-before對此變量的任意操作。
  4. happen-before的傳遞性原則:如果A操作 happen-before B操作,B操作happen-before C操作,那么A操作happen-before C操作。
  5. 線程啟動的happen-before原則:同一個線程的start方法happen-before此線程的其它方法。
  6. 線程中斷的happen-before原則:對線程interrupt方法的調用happen-before被中斷線程的檢測到中斷發(fā)送的代碼。
  7. 線程終結的happen-before原則:線程中的所有操作都happen-before線程的終止檢測。
  8. 對象創(chuàng)建的happen-before原則:一個對象的初始化完成先于他的finalize方法調用。

JMM只有在不出現(xiàn)上述8中情況時,才不會觸發(fā)指令重排效果。不需要過分的關注happens-before原則,只需要可以寫出線程安全的代碼就可以了。

volatile

如果需要讓程序對某一個屬性的操作不出現(xiàn)指令重排,除了滿足happens-before原則之外,還可以基于volatile修飾屬性,從而對這個屬性的操作,就不會出現(xiàn)指令重排的問題了。

volatile如何實現(xiàn)的禁止指令重排?
內存屏障概念。將內存屏障看成一條指令。 會在兩個操作之間,添加上一道指令,這個指令就可以避免上下執(zhí)行的其他指令進行重排序。

http://www.risenshineclean.com/news/115.html

相關文章:

  • 石家莊網絡公司排名/南昌seo公司
  • 免費的行情軟件網站在線使用/企業(yè)網站建設多少錢
  • 山東省建設工程注冊中心網站/114黃頁
  • 手機網站后臺/seo是什么?
  • 做黨和人民滿意的好教師PPT網站/百度瀏覽器廣告怎么投放
  • 中國百強城市榜單排名/seo sem推廣
  • 南寧機關兩學一做網站/網絡營銷八大工具
  • 天津市建設工程信息交易網/seo免費培訓教程
  • 做餐飲要看的網站/seo批量建站
  • 北京做網站浩森宇特/品牌推廣軟文200字
  • 靖江網站建設/百度小說風云榜今天
  • 漳州專業(yè)網站建設費用/青島seo用戶體驗
  • 天津做網站要多少錢/百度seo流量
  • 專業(yè)建設網站公司哪家好/優(yōu)化深圳seo
  • 企業(yè)網站服務器選擇/torrentkitty磁力官網
  • 石獅市網站建設/seo 頁面鏈接優(yōu)化
  • 上海網站排名團隊/百度搜索引擎的網址是
  • ds216j做網站/跨境電商培訓
  • 微網站 pc網站同步/長沙靠譜關鍵詞優(yōu)化公司電話
  • 人設生成器網站/怎么把平臺推廣出去
  • 溧陽手機網站哪里做/學it什么培訓機構好
  • 找人網站/網頁模板怎么用
  • 揭陽網站制作案例/如何在各種網站投放廣告
  • 網站免費正能量入口/百度首頁推薦關不掉嗎
  • 網站建設步驟及分工/優(yōu)秀軟文范例100字
  • 對網站進行優(yōu)化/網站排名快速提升
  • 武城網站建設費用/品牌營銷公司
  • 佛山市企業(yè)網站建設平臺/太原關鍵詞優(yōu)化軟件
  • 做網站大概價格/南昌seo排名優(yōu)化
  • 做網站的公司有前途嗎/如何制作網站和網頁