Java——線程鎖,死鎖,等待喚醒機制

一、線程鎖

線程安全問題

其實,線程安全問題都是由全局變量及靜態變量引起的。若每個線程中對全局變量、靜態變量只有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程同時執行寫操作,一般都需要考慮線程同步,否則的話就可能影響線程安全。

由于線程休眠的特性,從哪休眠就從哪繼續執行(一個線程的事情還沒干完就被其他線程擠下去了),回來繼續干就會導致操作的全局變量或靜態變量出現問題。

為了解決這個問題,我們就需要讓線程執行完畢(不能被其他線程擠下去),以下是幾種解決辦法。

1、同步代碼塊

保證代碼塊執行完畢,再切換線程。

公式:

synchronized(任意對象){

  線程要操作的共享數據

}

調用類

1

2

3

4

5

6

7

8

9

10

11

12

public?class?ThreadDemo {

????public?static?void?main(String[] args) {

????????Ticket tk =?new?Ticket();

????????Thread t01 =?new?Thread(tk);

????????Thread t02 =?new?Thread(tk);

????????Thread t03 =?new?Thread(tk);

?

????????t01.start();

????????t02.start();

????????t03.start();

????}

}

同步代碼塊

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public?class?Ticket?implements?Runnable {

????//定義出售的票源

????private?int?ticket =?100;

?

????public?void?run() {

????????while?(true) {

????????????// 因為里面可以填任意對象,所以可以使用this(表示當前實例化的Ticket對象tk)

????????????synchronized?(this) {

????????????????//對票數判斷,大于0,可以出售,變量--操作

????????????????if?(ticket >?0) {

????????????????????System.out.println(Thread.currentThread().getName() +?" 出售第 "?+ ticket--);

????????????????}

????????????}

????????}

????}

}

同步代碼塊中的鎖對象可以是任意的對象;但多個線程時,要使用同一個鎖對象才能夠保證線程安全。

2、同步方法

還可以將需要同步的代碼塊,抽出來一個方法,使用synchronized字段修飾。

public?synchronized?void method(){

  可能會產生線程安全問題的代碼

}

同步方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

public?class?Ticket?implements?Runnable {

????//定義出售的票源

????private?int?ticket =?100;

?

????public?void?run() {

????????while?(true) {

????????????func();

????????}

????}

?

????private?synchronized?void?func() {

????????//對票數判斷,大于0,可以出售,變量--操作

????????if?(ticket >?0) {

????????????System.out.println(Thread.currentThread().getName() +?" 出售第 "?+ ticket--);

????????}

????}

}

同步方法中的鎖對象是this,如果是靜態同步方法的話同步鎖是本類類名.class

3、Lock接口

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

public?class?Ticket?implements?Runnable{

?

????//定義出售的票源

????private?int?ticket =?100;

????//在類的成員位置,創建Lock接口的實現類對象

????private?Lock lock =?new?ReentrantLock();

?

????public?void?run(){

????????while(true){

????????????//調用Lock接口方法lock獲取鎖

????????????lock.lock();

????????????//對票數判斷,大于0,可以出售,變量--操作

????????????if( ticket >?0){

????????????????try{

????????????????????//執行可能會引發線程安全問題的代碼

????????????????????System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);

????????????????}catch(Exception ex){

?

????????????????}finally{

????????????????????//釋放鎖,調用Lock接口方法unlock

????????????????????lock.unlock();

????????????????}

????????????}

????????}

????}

}

二、死鎖

同步鎖使用的弊端:當線程任務中出現了多個同步(多個鎖)時,如果同步中嵌套了其他的同步。這時容易引發一種現象:程序出現無限等待,這種現象我們稱為死鎖。這種情況能避免就避免掉。

三、等待喚醒機制

線程之間的通信:

多個線程在處理同一個資源,但是處理的動作(線程的任務)卻不相同。通過一定的手段使各個線程能有效的利用資源。而這種手段即——等待喚醒機制。

等待喚醒機制

等待喚醒機制所涉及到的方法:

其實,所謂喚醒的意思就是讓線程池中的線程具備執行資格。必須注意的是,這些方法都是在同步中才有效。同時這些方法在使用時必須標明所屬鎖,這樣才可以明確出這些方法操作的到底是哪個鎖上的線程。

仔細查看JavaAPI之后,發現這些方法并不定義在Thread中,也沒定義在Runnable接口中,卻被定義在了Object類中,為什么這些操作線程的方法定義在Object類中?

因為這些方法在使用時,必須要標明所屬的鎖,而鎖又可以是任意對象。能被任意對象調用的方法一定定義在Object類中。

復制代碼

 1 package cn.x5456.demo;2 3 public class ThreadDemo {4     public static void main(String[] args) {5         Resource r = new Resource();6 7         // 共享數據8         Input in = new Input(r);9         Output out = new Output(r);
10 
11         Thread tin = new Thread(in);
12         Thread tout = new Thread(out);
13 
14         tin.start();
15         tout.start();
16     }
17 }

復制代碼

復制代碼

 1 package cn.x5456.demo;2 3 public class Input implements Runnable{4     private Resource r;5     int i = 0;6 7     public Input(Resource r){8         this.r=r;9     }
10 
11 
12     public void run() {
13         while (true){
14             synchronized (r){   //要使用同一個對象來看著Input和Output兩個同步方法(否則就各自走各自的了)
15                 if(r.flag){
16                     try {
17                         r.wait();   //使用同一個對象才能等待+啟動
18                     } catch (InterruptedException e) {
19                         e.printStackTrace();
20                     }
21                 }
22                 if(i%2==0){
23                     r.name = "張三";
24                     r.sex = "男";
25                 }else{
26                     r.name = "lisi";
27                     r.sex = "nv";
28                 }
29                 i++;
30                 r.flag = true;
31                 r.notify();     //喚醒另一邊
32             }
33         }
34     }
35 }

復制代碼

復制代碼

 1 package cn.x5456.demo;2 3 public class Output implements Runnable{4     private Resource r;5 6     public Output(Resource r) {7         this.r = r;8     }9 
10 
11     @Override
12     public void run() {
13         while (true){
14             synchronized (r){
15                 if(!r.flag){
16                     try {
17                         r.wait();
18                     } catch (InterruptedException e) {
19                         e.printStackTrace();
20                     }
21                 }
22                 System.out.println(r.name+".."+r.sex);
23                 //標記改成false,喚醒對方線程
24                 r.flag = false;
25                 r.notify();
26             }
27         }
28     }
29 }

復制代碼

復制代碼

1 package cn.x5456.demo;
2 
3 public class Resource {
4     String name;
5     String sex;
6     boolean flag = false;
7 }

復制代碼

?

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

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

相關文章

資深大牛帶你了解源碼!關于Android程序員最近的狀況,大廠內部資料

前言 回顧一下自己這段時間的經歷,因公司突然通知裁員,我匆匆忙忙地出去面了幾家,但最終都沒有拿到offer,我感覺今年的寒冬有點冷。公司開始第二波裁員,我決定主動拿賠償走人。后續的面試過程我做了一些準備&#xff…

AE 新建項目(一)(持續更新,做到哪算哪)

開發環境 工具:Visual Studio 2012、ArcEngine10.4.1 語言:C# 開發步驟 1、打開Visual Studio 2012,選擇新建項目,創建一個.NET Framework4的,Windows窗體應用程序。取名Demo 2、工具箱中,拖一個splitConta…

基于redis分布式鎖實現的多線程并發程序

前兩個版本的代碼 都或多或少存在一定的問題,雖然可能微乎其微,但是程序需要嚴謹再嚴謹, 第一個版本問題: 局限于單機版,依賴于 Jvm的鎖 第二個版本問題: 極端情況下,解鎖邏輯的問題&#xf…

day15 Ui自動化元素的定位

day15 元素的定位Ui自動化元素的定位1、火狐瀏覽器安裝try xpath2、元素定位思路:(1)查看頁面元素,確認能夠唯一定位到元素的屬性,比如id,文案3、學習xpath cssSelector 手寫定位方式xpath(xpat…

幾張圖可以理解GC JVM調優的內容

public class ApiPurchaseOrderServiceApp {public static void main(String[] args) throws Exception {ApiPurchaseOrderServiceApp mnew ApiPurchaseOrderServiceApp();m.compute();//棧System.out.println("ok");//方法出口}public int compute(){int a1;//局部…

靈魂拷問!一起刷完了這份1307頁的安卓面試寶典吧,不吃透都對不起自己

前言 每個程序員都有一個夢想,那就是進一線互聯網公司深造,不要跟我說你不想進去,如果給你一個這樣的平臺,不管是薪資待遇還是接觸的高度來說,對我們程序員來說都是一個機會,我以前有一個同事,…

ShardingSphere分庫分表實戰

ShardingSphere是一套開源的分布式數據庫中間件解決方案組成的生態圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(計劃中)這3款相互獨立的產品組成。 他們均提供標準化的數據分片、分布式事務和數據庫治理功能,可適用于…

靈魂拷問!細數Android開發者的艱辛歷程,成功入職阿里

什么是中年危機 根據權威數據顯示,國內IT程序員鼎盛時期是在25-27歲左右,30歲對于程序員而言完全是一個38線,接著就是轉業轉崗的事情,這一點在業界也算是一個共識了。 大學畢業步入IT行業普遍年齡也是在22歲左右,然而…

React 深度學習:ReactFiber

packages/react-reconciler/src/ReactFiber.js Fiber // A Fiber is work on a Component that needs to be done or was done. There can // be more than one per component. // Fiber 是 Component 上需要完成或已經完成工作。每個組件可以有多個 fiber。 export type Fiber…

JMM模型到并發編程

電腦:內存 L1 L2 L3 緩存 CPU ctrlatldel就可以看到 Java 有線程內存,在執行線程的時候,會從主內存把變量加載到工作內存(緩存),所以,在多線程同時改變一個靜態變量時候,實際是分開…

焦慮的移動互聯網開發者如何破局?專題解析

尷尬的35歲 不知道是哪個人提出的職場35歲就要面臨被淘汰的定律,因為35歲定律本來就是個偽命題,尤其是在IT行業! 現在年八九百萬的大學生畢業,他們雖然年輕活力,但是很多企業也將之“拒之門外”。 35歲的不要,二十幾…

17.前端路由router-07keep-alive

keep-alive是Vue提供的一個抽象組件,用來對組件進行緩存,從而節省性能, 由于是一個抽象組件,所以在v頁面渲染完畢后不會被渲染成一個DOM元素 當組件在keep-alive內被切換時組件的activated、deactivated這兩個生命 周期鉤子函數會…

jvm指令碼

建議直接復制保存至本地,研究jvm運行,執行指令非常有幫助 一、未歸類系列A 此系列暫未歸類。 指令碼 助記符 說明 0x00 nop 什么都不做 0x01 aconst_null 將null推送至棧頂 二、const系列 該系列命令主要負責把簡單的數值類型送到棧頂。該系列命令不帶參…

來一份全面的面試寶典練練手,面試真題解析

前言 下面的題目都是大家在面試字節跳動或者其它大廠面試時經常遇到的,如果大家有好的題目或者好的見解歡迎分享。 參考解析:郭霖、鴻洋 內容特點:條理清晰,含圖像化表示更加易懂。 內容概要:包括 Handler、Activi…

使用IDEA創建Maven項目和Maven使用入門(配圖詳解)

本文詳解的講解了使用IDEA創建Maven項目,及Maven的基礎入門。 1、打開IDEA,右上角選擇File->New->Project 2、如圖中所示選擇Maven(可按自己所需添加,否則加載時速度很慢) 3、添加項目所需Groupld,ArtifactId,Ve…

jvisualvm安裝Visual GC插件

給jdk自帶的jvisualvm安裝Visual GC插件,遇到Were sorry the java.net site has closed(我們很抱歉java.net網站已經關閉) 1、找到新的更新地址 visualvm新訪問地址:https://visualvm.github.io/index.html 進入“Plugins”&…

來自阿里巴巴佛系安卓程序員的指南,專題解析

開頭 中國互聯網發展的這些年,如今90后程序員是中國程序員的主力軍,互聯網的熱潮也讓一批批00后蠢蠢欲動,嘗試涌入互聯網圈。 當程序員容易,當一個優秀的程序員需要不斷學習,從初級程序員到高級程序員,從…

C#在WinForm中打開控制臺顯示

引用: namespace 測試使用 {public partial class Form1 : Form{[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError true)][return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bo…

Redis+AQS

前言 對于java的單進程應用來說,存在資源競爭的場景可以使用synchronized關鍵字和Lock來對資源進行加鎖,使整個操作具有原子性。但是對于多進程或者分布式的應用來說,上面提到的鎖不共享,做不到互相通訊,所以就需要分…

Laravel 除了首頁能正常訪問,其它頁面均404

在寶塔系統上通過一鍵源碼配置laravel框架后,發現除了首頁能夠正常訪問,其它的頁面均返回的404,后經過比對已經網上查資料,發現是nginx的配置文件出了問題 1.找到配置文件 寶塔系統地址:/www/server/panel/vhost/nginx 2.在新建網…