JAVA線程及簡單同步實現的原理解析

JAVA線程及簡單同步實現的原理解析html

摘要: JAVA線程及簡單同步實現的原理解析線程1、內容簡介:  本文主要講述計算機中有關線程的相關內容,以及JAVA中關於線程的基礎知識點,爲之後的深刻學習作鋪墊。若是你已是高手了,那麼這篇文章並不適合你。java

線程
1、內容簡介:
  本文主要講述計算機中有關線程的相關內容,以及JAVA中關於線程的基礎知識點,爲之後的深刻學習作鋪墊。若是你已是高手了,那麼這篇文章並不適合你。
2、隨筆正文:
一、計算機系統組成
  計算機系統由計算機硬件系統和軟件系統組成。咱們今天要說的線程和硬件系統中的cpu中央處理器,及軟件系統中的操做系統,進程等有比較緊密的聯繫。操做系統是軟件中比較特殊的存在,與硬件系統直接交互,其餘程序(軟件)運行在操做系統之上。
二、cpu簡單說明
  硬件系統中特別重要的一項就是處理器CPU,與咱們所說的線程有很是緊密的聯繫。cpu中有幾項參數,以及如何查看該信息,在下文逐一說明:
塊數:民用pc機,基本都是一塊物理cpu,每塊主板上只能裝一塊cpu。
核心數:也就是單塊物理cpu是由幾組處理芯片組,組成的。4核心 8核心等。
線程數:老款cpu都是單線程的,及一組芯片組只能運行一個線程。現款因特爾cpu大多支持超線程技術可支持多個邏輯線程。可是須要操做系統及相關編程語言的支持,JAVA相較C++在多線程方面能表現的更出色。
主頻:單位GHZ(hz赫茲 每秒的週期性變更重複次數)在計算機中即高低電平變化一次,能夠產生兩個不一樣的電信號0、1。以個人CPU I5-4200M 2.5GHZ 舉例,及cpu能夠每秒完成25億次震盪! 也就是說主頻越高理論上計算能力越強,處理計算機指令越快。可是並不表明計算機總體運算速度約高,這點一般知足水桶效應,而cpu一直穩居長板地位。
緩存:cpu內置緩存,很小一般爲幾Mb至十幾Mb,和cpu交互更頻繁,速度也遠高於普通運行內存,提升cpu處理能力的有效手段。
查看cpu參數指令:
DOS命令chrome

三、關係梳理
  操做系統,程序,進程,線程之間的關係梳理、
  程序:是計算機上的靜態代碼,指令文件集合,是靜態的存在。好比:QQ,LOL等
  進程:程序的執行實體(過程),持有及分配資源的主體。chrome.ext,QQ.exe等執行進程。
  線程:是進程中的勞動力,由進程建立,完成指定任務後結束。
  關係:
    操做系統 1 ——> n 程序 1 ——> n 進程 1 ——> n 線程
     平臺       集合     資源     幹活的
  普通進程建立線程去完成指定的計算機指令,這個時候須要調用系統資源如cpu進行運算,可是用戶線程並不能直接驅動硬件,而是經過操做系統去統一分配、控制硬件的使用。編程

四、進程、線程基本狀態
  五個基本狀態,建立和終止不說了。計算機中的線程建立以後會進入就緒狀態,當cpu爲此線程分配時間片時,線程由就緒轉爲執行狀態,開始幹活,當時間片結束時回到就緒狀態等待下次獲取時間片,循環直到任務完成,當任務完成時,線程終止(死亡)。若在執行過程當中遇到耗時操做好比IO或者JAVA中的線程休眠等,會進入阻塞狀態,阻塞結束會進入就緒狀態繼續排隊等待被分配時間片。緩存

五、JAVA中的線程
  java中提供了兩種方式去建立線程,繼承類和實現接口。因爲java中單繼承機制的限制,大多數狀況下使用實現Runnable接口的形式建立線程。
1 、繼承Thread類
繼承Thread類
二、實現Runnable接口
實現Runnable接口
三、線程的經常使用方法網絡

1 start()
2 //啓動線程,調用run方法
3 sleep()
4 //線程休眠,進入阻塞狀態,讓出時間片,但不會讓出鎖
5 Thread.currentThread()
6 //獲取當前執行線程
7 wait/notify()
8 //僅能存在synchronized代碼塊中,wait線程休息,讓出時間片,進入等待狀態,notify()喚醒該線程;該方法存在重載
9 join()
10 //等待此線程執行完畢
11 setDaemon()
12 //設置守護線程,守護線程是服務線程,當用戶線程結束,守護線程自動結束
13 yield()
14 //主動讓出時間片給其餘線程
15 interrupt()
16 //中斷線程,不推薦
17 get/setId()
18 //設置獲取線程id
19 get/setName()
20 //設置獲取線程名
21 get/setPriority()
22 //設置獲取線程優先級,理論上優先級越高,獲取時間片的機率越大,默認是5最高10最小1
複製代碼
四、JAVA中的線程狀態圖
五、線程練習
簡單模擬多線程購票業務
售票業務
  在不作任何控制的狀況下,出錯的概率很小,我反覆測試幾回,結果基本都正確!分析緣由:業務自己相對簡單,沒有耗時操做,每一個時間片基本能保證線程將本次任務執行完畢!也就是將票數減一併打印內容。
  爲了模擬在售票前雙方的問詢階段及付款階段的等待,在售票前(後)加入Thread.sleep(ms) 模擬耗時操做。
加入線程休眠
  改動後系統出現bug同一張票被售出了屢次,而且可能將票賣出負數。究其緣由:線程之間的數據爭用問題,咱們將引入JAVA內存模型進行分析(圖片來自網絡侵刪)
  首先咱們須要知道幾個概念,以下:
  共享變量:主內存中存在被多個線程同時用到的變量,在多個線程中存在相應副本變量。
  可見性:線程對共享變量的值進行修改,可否被其餘線程可見。
  變量訪問規則:   一、線程對共享變量的操做只能在本身工做內存中的副本。
            二、工做內存中的變量變化須要經過主內存傳遞。
六、實現同步
  實現同步即實現共享變量可見性,工做內存1 ——> 主內存 ——>工做內存2,在數據傳遞的兩個環節中出現問題都會對同步形成影響,從而影響執行結果。
  synchronized實現同步
  synchronized 能夠實現指令的原子性,及共享變量的可見性。
  原子性:synchronize修飾的方法或者代碼塊會獲取互斥鎖,保證同一時間只能有一個對象訪問該方法或代碼塊,將其做爲一個總體,保證了原子性。
​   可見性:加鎖後,先清空工做內存,同步主內存中的共享變量。解鎖前,先將工做內存中的變量同步到主內存,再釋放鎖。
  因此結合上述例子,爲sellTickets()方法加鎖便可實現同步;或者對核心代碼片斷加鎖;
複製代碼
private synchronized boolean sellTickets() { //… 省略中間代碼
}
  //或者以下實現
  
synchronized(this){
[Java] 純文本查看 複製代碼
?
1
//this指的是調用sellTickets()的對象
}多線程

七、volatile關鍵字
  共享變量(類的成員變量、類的靜態成員變量)被volatile修飾以後,那麼就具有了兩層語義:
  原理:被volatile修飾的變量所生成彙編代碼時有lock前綴,生成"內存屏障"。
    1)保證了不一樣線程對這個變量進行操做時的可見性,即工做內存中的變量值在修改後會被當即同步到主內存中;
    2)而且使其餘線程中的緩存無效,這樣當其餘線程在訪問共享變量時就必須取主內存中獲取;
    3)禁止進行指令重排序;
  綜上所述,volatile能夠保證可見性,但不能保證原子性;
  舉例分析:編程語言

volatile int number = 0 ;
number ++ ;
/*
[Java] 純文本查看 複製代碼
?學習

操做能夠解析成三步: 1.獲取number中的值測試

2.計算加1操做 
              3.number = 0 + 1;

在一個時間片中,雖然volatile修飾的number必定會被當即同步到主內存中,但不能保證完整執行這三步,因此不能保證++操做的原子性 。
原文地址https://www.cnblogs.com/lijiz...

相關文章
相關標籤/搜索