Java多線程 ——線程基礎和鎖鎖鎖

  • Java多線程(一)
    • 一、線程的定義
    • 二、Synchronize線程同步
    • 三、偏向鎖、自旋鎖、重量級鎖
    • 四、volatile關鍵字
      • 4.1.普通變量運算的物理意義
      • 4.2.有無解決的方案
      • 4.3.volatile的幾個特性(參考https://www.cnblogs.com/kubidemanong/p/9505944.html)
    • 五、Compare And Swap無鎖自旋優化技術和ABA版本號機制
      • 5.1.CAS操作原理
      • 5.2.atomic包
      • 5.3.關于大并發下AtomicInteger和LongAdder和Sync的效率(百萬并發以上)
    • 六、樂觀鎖和悲觀鎖(參考https://blog.csdn.net/qq_34337272/article/details/81072874)
    • 七、公平鎖、非公平鎖
      • 7.1.概念
      • 7.3.重入鎖

?

一、線程的定義

 

一個程序中不同的分支進行執行

二、Synchronize線程同步

概念:線程同步指的是,即當有一個線程在對內存進行操作時,其他線程都不可以對這個內存地址進行操作,直到該線程完成操作, 其他線程才能對該內存地址進行操作。

多線程訪問同一個資源會產生線程安全問題,所以需要進行加鎖。

 

package com.littlepage.test; class MyThread implements Runnable{ //票數是多個線程的共享資源 private int ticket = 10; @Override public void run() { while(ticket > 0) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"還剩下"+ticket--+"張票"); } } } public class Test { public static void main(String[] args) { MyThread thread1 = new MyThread(); new Thread(thread1,"黃牛A").start(); new Thread(thread1,"黃牛B").start(); new Thread(thread1,"黃牛C").start(); } }

多運行幾次,發現出現了負數

這就是線程安全問題,為了解決這個問題,我們采用加鎖進行控制

 

@Override public synchronized void run() { while(ticket > 0) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"還剩下"+ticket--+"張票"); } }

增加了一個鎖之后,打印結果為

我們在方法上加synchronize,實際上等同下面這個寫法

 

class MyThread implements Runnable{ //票數是多個線程的共享資源 private int ticket = 10; @Override public void run() { synchronized (MyThread.class) { while(ticket > 0) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"還剩下"+ticket--+"張票"); } } } }

這個MyThread.class是一個互斥鎖(mutex),C程序中,我們mutex的實現是,指定一個信號量,對其進行pv操作實現鎖機制,Java中的對象鎖,深糾底層,原理是鎖是存在對象頭里面的,什么是Java對象頭?Java對象頭是一個與對象本身無關的一個額外區域,我們在使用鎖的時候,實際上對Java對象頭內部指針進行了操作。

三、偏向鎖、自旋鎖、重量級鎖

  • Java在使用synchronize關鍵字,首先在Java對象頭進行markword,記錄這個線程id,只有一個線程對這個對象加鎖,這個鎖叫做偏向鎖。
  • 偏向鎖如果有線程爭用,那么升級為自旋鎖?一個鎖如果被使用,那么另外一個線程打算爭搶這把鎖,則會陷入while循環,形成自旋。這叫做自旋鎖。
  • 旋10次之后,升級為重量級鎖。重量級鎖以OS為主體。那么重量級鎖不會占用CPU。
  • 注:鎖不能降級

四、volatile關鍵字

4.1.普通變量運算的物理意義

一般程序來說,我們定義一個a ,使用a++進行操作,在物理上,實際是將a放入高速緩存(cache),經過運算后,再放回內存,這樣就出現線程安全問題,幾個線程同時進行a++操作,可能沒有達到最終加值效果。在比如是類似銀行匯款的業務中,那么問題就出來了。

4.2.有無解決的方案

volatile關鍵字,在Java語言和C程序中都有,這個關鍵字可以硬性規定,先將變量加鎖,使變量在主存中進行計算,之后再釋放鎖,所以,變量不會出現運算失誤狀態。

4.3.volatile的幾個特性(參考https://www.cnblogs.com/kubidemanong/p/9505944.html)

  • 可見性

在多線程環境下,如果一個線程修改了,其他線程能立即讀到。這是因為他們讀取的時候不會先把變量讀進自己的緩存,直接在內存讀取

  • 緩存一致性協議

線程中處理器一直在總線上進行查看進行探測情況,一旦發現其他處理器要修改這個內存地址的值,那么,就讓自己的高速緩存區變為無效狀態,從內存進行讀取

  • 有序型
 

int a=1; int b=2;

我們寫完這個話后,因為無論執行哪句話都沒影響,所以,虛擬機會對這兩句指令進行重排序、

所以,我們可以使用volatile保證有序

重排序會遇到線程安全問題

五、Compare And Swap無鎖自旋優化技術和ABA版本號機制

5.1.CAS操作原理

CAS操作:CAS存在3個參數,變量V,舊值A,新值B,內存值與B相等的時候,才會去修改B,否則直接返回。

CAS是一種CPU原語。

 

cas(V,Expected,NewValue) if V==E E=New otherwise try again or fail -CPU對原語支持

java.util.concurrent.atomic下有很多CAS操作的類

5.2.atomic包

例如AtomicInteger,這個對象調用incrementAndGet方法,和int a=0;a++;不一樣,這個是線程安全的,無論起多少個線程,都能在無鎖狀態進行線程安全操作。在舊版本Java中,沒有偏向,自旋,重量級升級說吧的概念,所以AtomicInteger速度會比synchronize快很多,因為是無鎖操作。現在來講,速度應該差不多。

 

public static void main(String[] args){ AtomicInteger count = new AtomicInteger(0); for(int i=0;i<1000;i++) { new Thread(new Runnable() { @Override public void run() { count.incrementAndGet(); } }); } }

包內其他對象

5.3.關于大并發下AtomicInteger和LongAdder和Sync的效率(百萬并發以上)

5.4.版本號機制(參考https://blog.csdn.net/qq_34337272/article/details/81072874)

一般是在數據表中加上一個數據版本號version字段,表示數據被修改的次數,當數據被修改時,version值會加一。當線程A要更新數據值時,在讀取數據的同時也會讀取version值,在提交更新時,若剛才讀取到的version值為當前數據庫中的version值相等時才更新,否則重試更新操作,直到更新成功。

5.5.ABA問題(參考https://blog.csdn.net/qq_34337272/article/details/81072874)

如果一個變量V初次讀取的時候是A值,并且在準備賦值的時候檢查到它仍然是A值,那我們就能說明它的值沒有被其他線程修改過了嗎?很明顯是不能的,因為在這段時間它的值可能被改為其他值,然后又改回A,那CAS操作就會誤認為它從來沒有被修改過。這個問題被稱為CAS操作的?"ABA"問題。

JDK 1.5 以后的?AtomicStampedReference 類就提供了此種能力,其中的?compareAndSet 方法就是首先檢查當前引用是否等于預期引用,并且當前標志是否等于預期標志,如果全部相等,則以原子方式將該引用和該標志的值設置為給定的更新值。

六、樂觀鎖和悲觀鎖(參考https://blog.csdn.net/qq_34337272/article/details/81072874)

  • 樂觀鎖

總是假設最好的情況,每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號機制和CAS算法實現。樂觀鎖適用于多讀的應用類型,這樣可以提高吞吐量,像數據庫提供的類似于write_condition機制,其實都是提供的樂觀鎖。在Java中java.util.concurrent.atomic包下面的原子變量類就是使用了樂觀鎖的一種實現方式CAS實現的。

  • 悲觀鎖

總是假設最壞的情況,每次去拿數據的時候都認為別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖(共享資源每次只給一個線程使用,其它線程阻塞,用完后再把資源轉讓給其它線程)。傳統的關系型數據庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。Java中synchronized和ReentrantLock等獨占鎖就是悲觀鎖思想的實現。

七、公平鎖、非公平鎖

7.1.概念

公平鎖:加鎖之前先檢查是否有排隊等待的線程,有的話優先處理排前面的線程,先來先得。

非公平鎖:線程加鎖時直接嘗試獲取,獲取不到就到隊尾等待

7.2.Java中的公平鎖和非公平鎖

 

//非公平鎖 Lock nonFairLock=new ReentrantLock(true);//默認空參是true //公平鎖 Lock fairLock=new ReentrantLock(false);

注:非公平鎖比公平鎖快很多

7.3.重入鎖

ReetranLock含義是重入鎖,什么意思呢,可以進行加鎖多次,和解鎖多次,比如

 

public class NoVisibility{ public static void main(String[] args){ Lock lock=new ReentrantLock(); lock.lock(); lock.lock(); lock.unlock(); lock.unlock(); } }

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/386590.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/386590.shtml
英文地址,請注明出處:http://en.pswp.cn/news/386590.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

阿里P7級別面試經驗總結,進階學習資料!

一、前言 本人面試已經很久之前了&#xff0c;分享一下我做美團面試官的經歷吧。 美團上海面試&#xff0c;2-1及以下美團是不社招的&#xff0c;校招和2-2~2-3社招一般是三面&#xff0c;格外優秀3-1及以上會加簽面試。初面技術基礎&#xff0c;二面業務感知和技術項目&#…

C 預處理指令

0. Overview C的預處理指令格式為#name&#xff0c;均以#開頭&#xff0c;#和指令名之間不可有空白字符&#xff0c;#前可以有空字符&#xff0c;但為增強可讀性&#xff0c;一般應從第一列開始 #name不能由宏展開得來&#xff0c;name也不能由宏展開得來&#xff0c;如 // Wro…

Windows NAT端口映射

Windows本身命令行支持配置端口映射&#xff0c;條件是已經安裝了IPV6&#xff0c;啟不啟用都無所謂&#xff0c;我在win7和server2008上是可以的。xp&#xff0c;2003裝了ipv6協議也是可以的。 CMD下操作 增加端口映射&#xff0c;將10.10.10.10的8080映射到10.10.10.11的80…

阿里P8大牛親自教你!史上最全的Android面試題集錦,這原因我服了

一、架構師專題 想要掌握復雜的技術&#xff0c;必須要理解其原理和架構。本模塊結合實際一線互聯網大型項目理解架構思維&#xff0c;抽絲剝繭&#xff0c;層層深入&#xff0c;幫助大家成為Android架構師&#xff0c;在思想上對架構認識有一次升華&#xff0c;并知其所以然&a…

面向對象程序設計——UML分析和本學期總結

? 隨著第四單元UML第二次作業的結束&#xff0c;本學期的OO學習也宣告結束了&#xff08;但還得寫博客&#xff09;&#xff0c;下面就對本單元和本次作業做一個總結。 第四單元兩次作業的架構設計 ? 本單元是對UML的結構進行解析&#xff0c;第一次作業是對UML類圖的解析&am…

docker linux k8s kubeadm

一. 安裝docker 1.添加yum國內依賴 yum -y install yum-utils yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo2.安裝docker yum -y install docker-ce docker-ce-cli containerd.io3.啟動docker systemctl start docker4…

小程序FMP優化實錄,大廠面試題匯總

前言 金九銀十面試季&#xff0c;相信大家肯定急需一套Android面試寶典&#xff0c;今天小編就給大家準備了我珍藏已久的Android高階面試寶典&#xff0c;一份超級詳細的Android面試必備知識點&#xff0c;供大家學習 &#xff01; 想必每一個安卓程序員都有追求大廠的決心&a…

文件CRC和MD5校驗

文件CRC和MD5校驗 CRC和MD5用于文件和數據的傳輸校驗&#xff0c;以確認是否接收成功。 unit CRCMD5;interface { 獲取文件CRC校驗碼 } function GetFileCRC(const iFileName: string): String; { 獲取字符串CRC校驗碼 } function GetStringCRC(const Str: string): Cardinal; …

Oracle字符分隔函數(split)

為了讓 PL/SQL 函數返回數據的多個行&#xff0c;必須通過返回一個 REF CURSOR 或一個數據集合來完成。REF CURSOR 的這種情況局限于可以從查詢中選擇的數據&#xff0c;而整個集合在可以返回前&#xff0c;必須進行具體化。Oracle 9i 通過引入的管道化表函數糾正了后一種情況。…

已成功拿下字節、騰訊、脈脈offer,吐血整理

為什么想跳槽&#xff1f; 簡單說一下當時的狀況&#xff0c;我在這家公司做了兩年多&#xff0c;這兩年多完成了一個大項目&#xff0c;作為開發的核心主力&#xff0c;開發壓力很大&#xff0c;特別是項目上線前的幾個月是非常辛苦&#xff0c;幾乎每晚都要加班到12點以后&a…

復雜HTML解析

#再端一碗BeautifulSoup #獲取《戰爭與和平》中的人物名字from urllib.request import urlopen from bs4 import BeautifulSouphtml urlopen("http://www.pythonscraping.com/pages/warandpeace.html") bsObj BeautifulSoup(html,html.parser)#namelist bsObj.fin…

java main方法里調用mapper

在main方法中調用mybatis的mapper&#xff0c;一次性執行導入數據功能package com.runxsoft.test;import com.runxsoft.iutils.common.utils.UserUtils; import com.runxsoft.superwe.base.SqlVo; import com.runxsoft.superwe.base.mapper.ProtogenesisMapper; import com.run…

已成功拿下字節、騰訊、脈脈offer,滿滿干貨指導

開頭 籠統來說&#xff0c;中年程序員容易被淘汰的原因其實不外乎三點。 1、輸出能力已到頂點。這個人奮斗十來年了&#xff0c;依舊碌碌無為&#xff0c;很明顯這人的天花板就這樣了&#xff0c;說白了&#xff0c;天賦就這樣。 2、適應能力越來越差。年紀大&#xff0c;有家…

ServletRequest HttpServletRequest 請求方法 獲取請求參數 請求轉發 請求包含 請求轉發與重定向區別 獲取請求頭字段...

原文地址:ServletRequest HttpServletRequest 請求方法 獲取請求參數 請求轉發 請求包含 請求轉發與重定向區別 獲取請求頭字段ServletRequest 基本概念 JavaWeb中的 "Request"對象 實際為 HttpServletRequest 或者 ServletRequest, 兩者都為接口服務器接收請求…

c#掃描圖片去黑邊(掃描儀去黑邊)

/// <summary> /// 自動去除圖像掃描黑邊 /// </summary> /// <param name"fileName"></param> public static void AutoCutBlackEdge(string fileName) { //打開圖像 Bit…

已成功拿下字節、騰訊、脈脈offer,算法太TM重要了

一、背景介紹 從實用角度梳理一篇能夠幫大家快速掃盲的CMake基礎教程&#xff0c;也是對我目前負責項目的一次學習總結。既然選擇從項目實用性考慮&#xff0c;下面的講解內容可能并不一定完整&#xff0c;更多的是符合項目目前使用到的一些特性。 接下來正面回答這個問題&am…

SpringBoot2.0 Actuator 監控參數說明

主要內容更 監控參數說明 Maven坐標 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency><groupId>io.micrometer</groupId>&…

帶你一步一步深入Handler源碼,醍醐灌頂!

開頭 最近有粉絲反應&#xff0c;不想做安卓了&#xff0c;有朋友轉到前端了&#xff0c;安卓不行了&#xff0c;問我怎么辦&#xff1f; 自從RN&#xff0c;Weex這種跨平臺編程語言出來以后&#xff0c;安卓將死的言論總是不絕于耳。隨著頗有摧枯拉朽之勢Flutter的出現&…

Spring基于狀態機squirrel-foundation簡單使用

squirrel-foundation的一些使用方法在百度上資料還是比較少&#xff0c;我是根據以下三個大佬寫的文章借鑒的&#xff0c;在這里記錄一下。 1、squirrel-foundation-demo 2、Squirrel使用&#xff08;中文文檔&#xff09; 3、squirrel-foundation狀態機的使用細節 我在這里直接…

記得把每一次面試當做經驗積累,深夜思考

開頭 Android開發&#xff0c;假如開始沒有任何的開發經驗的話&#xff0c; 千萬不要著急&#xff0c;不要想著在短時間內就把一個語言學習好&#xff0c; 因為你之前沒有任何的學習經驗&#xff0c; 在這個過程中需要有耐心地學習完JAVA的基礎知識&#xff0c; 然后才開始踏上…