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

當(dāng)前位置: 首頁 > news >正文

滁州做網(wǎng)站電話號碼/seo推廣服務(wù)哪家好

滁州做網(wǎng)站電話號碼,seo推廣服務(wù)哪家好,蘇州房產(chǎn)網(wǎng),網(wǎng)頁設(shè)計基礎(chǔ)知識總結(jié)文章目錄并發(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)在內(nèi)存上的操作有一定差異的。 Java為了解決相同代碼在不同操作系統(tǒng)上出現(xiàn)的各種問題,用JMM屏蔽掉各種硬件和操作系統(tǒng)帶來的差異。
讓Java的并發(fā)編程可以做到跨平臺。 JMM規(guī)定所有變量都會存儲在主內(nèi)存中,在操作的時候,需要從主內(nèi)存中復(fù)制一份到線程內(nèi)存(CPU內(nèi)存),在線程內(nèi)部做計算。然后再寫回主內(nèi)存中(不一定)。
原子性的定義:原子性指一個操作是不可分割的,不可中斷的,一個線程在執(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);}

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

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

synchronized

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

CAS

compare and swap也就是比較和交換,他是一條CPU的并發(fā)原語。
他在替換內(nèi)存的某個位置的值時,首先查看內(nèi)存中的值與預(yù)期值是否一致,如果一致,執(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的基礎(chǔ)上幫助我們實現(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)多少次,如果超過這個次數(shù),直接失敗/或者掛起線程。(自旋鎖、 自適應(yīng)自旋鎖)
    • 可以在CAS一次失敗后,將這個操作暫存起來,后面需要獲取結(jié)果時,將暫存的操作全部執(zhí)行,再返回最后的結(jié)果。

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

  • 線程1從內(nèi)存位置V中取出A
  • 線程2從內(nèi)存位置V中取出A
  • 線程2進(jìn)行了寫操作,將B寫入內(nèi)存位置V
  • 線程2將A再次寫入內(nèi)存位置V
  • 線程1進(jìn)行CAS操作,發(fā)現(xiàn)V中仍然是A,交換成功
    盡管線程1的CAS操作成功,但線程1并不知道內(nèi)存位置V的數(shù)據(jù)發(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維護(hù)的state變量來實現(xiàn)鎖的操作。

ThreadLocal

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

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

    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本身不存儲數(shù)據(jù),像是一個工具類,基于ThreadLocal去操作ThreadLocalMap。
  • ThreadLocalMap本身就是基于Entry[]實現(xiàn)的,因為一個線程可以綁定多個ThreadLocal,這樣一來,可能需要存儲多個數(shù)據(jù),所以采用Entry[]的形式實現(xiàn)。
  • 每一個現(xiàn)有都自己獨立的ThreadLocalMap,再基于ThreadLocal對象本身作為key,對value進(jìn)行存取ThreadLocalMap的key是一個弱引用,弱引用的特點是,即便有弱引用,在GC時,也必須被回收。這里是為了在ThreadLocal對象失去引用后,如果key的引用是強(qiáng)引用,會導(dǎo)致 ThreadLocal對象無法被回收。

ThreadLocal內(nèi)存泄漏問題:

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

2、可見性

什么是可見性?

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

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

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

解決可見性的方式

volatile

volatile是一個關(guān)鍵字,用來修飾成員變量。

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

volatile的內(nèi)存語義:

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

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

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

synchronized

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

    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線程結(jié)束");});t1.start();Thread.sleep(10);flag = false;System.out.println("主線程將flag改為false");}

Lock

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

    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線程結(jié)束");});t1.start();Thread.sleep(10);flag = false;System.out.println("主線程將flag改為false");}

final

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

3、有序性

什么是有序性?

在Java中,.java文件中的內(nèi)容會被編譯,在執(zhí)行前需要再次轉(zhuǎn)為CPU可以識別的指令,CPU在執(zhí)行 這些指令時,為了提升執(zhí)行效率,在不影響最終結(jié)果的前提下(滿足一些要求),會對指令進(jìn)行重排。
指令亂序執(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)問題:
線程可能會拿到?jīng)]有初始化的對象,導(dǎo)致在使用時,可能由于內(nèi)部屬性為默認(rèn)值,導(dǎo)致出現(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í)行結(jié)果是不變的。 而且如果存在依賴的關(guān)系,那么也不可以做指令重排。

// 這種情況肯定不能做指令重排序 int i = 0;
i++;
// 這種情況肯定不能做指令重排序 int j = 200;
j * 100;
j + 100;
// 這里即便出現(xiàn)了指令重排,也不可以影響最終的結(jié)果,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方法的調(diào)用happen-before被中斷線程的檢測到中斷發(fā)送的代碼。
  7. 線程終結(jié)的happen-before原則:線程中的所有操作都happen-before線程的終止檢測。
  8. 對象創(chuàng)建的happen-before原則:一個對象的初始化完成先于他的finalize方法調(diào)用。

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

volatile

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

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

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

相關(guān)文章:

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