Java基礎 第四節 第二課

      網友投稿 540 2025-04-01

      線程安全

      概述

      案例

      模擬票

      測試類

      線程同步

      同步代碼塊

      格式

      同步鎖

      同步方法

      格式

      代碼

      Lock 鎖

      概述

      如果有過個線程在同時運行, 而這些線程可能會勇士運行這段代碼. 程序每次運行結果和單線程運行的結果是一樣的, 而其他的變量的值也和預期的是一樣的, 就是線程安全的.

      案例

      我們通過一個案例, 演示線程的安全問題:

      電影院要賣票, 我們模擬電影院的賣過程. 假設要播放的電影是 “郭德綱和他嫂子的愛情故事”. 本次電影的座位共有 100 個. (本場電影只能賣 100 張票)

      我們來模擬電影院的售票窗口, 實現多個窗口同時賣 “郭德綱和他嫂子的愛情故事” 這場電影票. (多個窗口一起賣這 100 張票)

      窗口采用線程對象來模擬, 票采用 Runnable 接口子類來模擬.

      模擬票

      public class Ticket implements Runnable { private int ticket = 100; /** * 執行賣票操作 */ @Override public void run() { // 每個窗口賣票的操作 // 窗口永遠開啟 while (true) { if (ticket > 0) { // 有票可賣 // 出票操作 // 使用sleep模擬一下出票時間 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // 獲取當前線程對象的名字 String name = Thread.currentThread().getName(); System.out.println(name + "正在賣: " + ticket--); } } } }

      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

      測試類

      Java基礎 第四節 第二課

      public class Test51 { public static void main(String[] args) { // 創建線程任務對象 Ticket ticket = new Ticket(); // 創建三個窗口對象 Thread t1 = new Thread(ticket, "窗口1"); Thread t2 = new Thread(ticket, "窗口2"); Thread t3 = new Thread(ticket, "窗口3"); // 同時賣票 t1.start(); t2.start(); t3.start(); } } 輸出結果: 窗口1正在賣: 99 窗口3正在賣: 98 窗口2正在賣: 100 窗口2正在賣: 97 窗口1正在賣: 96 窗口3正在賣: 95 窗口2正在賣: 94 窗口1正在賣: 93 窗口3正在賣: 92 窗口3正在賣: 91 窗口1正在賣: 90 窗口2正在賣: 89 窗口2正在賣: 88 窗口3正在賣: 86 窗口1正在賣: 87 窗口1正在賣: 85 窗口2正在賣: 84 窗口3正在賣: 83 窗口1正在賣: 82 窗口2正在賣: 81 窗口3正在賣: 80 窗口3正在賣: 79 窗口2正在賣: 78 窗口1正在賣: 77 窗口3正在賣: 76 窗口2正在賣: 75 窗口1正在賣: 74 窗口1正在賣: 73 窗口2正在賣: 72 窗口3正在賣: 71 窗口1正在賣: 70 窗口2正在賣: 69 窗口3正在賣: 68 窗口3正在賣: 67 窗口1正在賣: 65 窗口2正在賣: 66 窗口1正在賣: 64 窗口2正在賣: 62 窗口3正在賣: 63 窗口3正在賣: 61 窗口1正在賣: 60 窗口2正在賣: 59 窗口2正在賣: 58 窗口1正在賣: 57 窗口3正在賣: 56 窗口3正在賣: 55 窗口2正在賣: 53 窗口1正在賣: 54 窗口1正在賣: 52 窗口3正在賣: 51 窗口2正在賣: 50 窗口1正在賣: 49 窗口2正在賣: 48 窗口3正在賣: 47 窗口2正在賣: 46 窗口3正在賣: 45 窗口1正在賣: 44 窗口1正在賣: 43 窗口3正在賣: 42 窗口2正在賣: 41 窗口2正在賣: 40 窗口3正在賣: 39 窗口1正在賣: 38 窗口1正在賣: 37 窗口3正在賣: 36 窗口2正在賣: 35 窗口1正在賣: 34 窗口3正在賣: 33 窗口2正在賣: 32 窗口2正在賣: 31 窗口3正在賣: 30 窗口1正在賣: 29 窗口3正在賣: 28 窗口1正在賣: 27 窗口2正在賣: 26 窗口2正在賣: 25 窗口3正在賣: 24 窗口1正在賣: 23 窗口3正在賣: 22 窗口2正在賣: 21 窗口1正在賣: 22 窗口2正在賣: 20 窗口1正在賣: 19 窗口3正在賣: 18 窗口3正在賣: 17 窗口2正在賣: 16 窗口1正在賣: 15 窗口3正在賣: 14 窗口2正在賣: 13 窗口1正在賣: 12 窗口1正在賣: 11 窗口2正在賣: 10 窗口3正在賣: 9 窗口3正在賣: 8 窗口2正在賣: 7 窗口1正在賣: 6 窗口2正在賣: 5 窗口1正在賣: 5 窗口3正在賣: 4 窗口2正在賣: 3 窗口1正在賣: 2 窗口3正在賣: 1 窗口2正在賣: 0 窗口1正在賣: -1

      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

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      88

      89

      90

      91

      92

      93

      94

      95

      96

      97

      98

      99

      100

      101

      102

      103

      104

      105

      106

      107

      108

      109

      110

      111

      112

      113

      114

      115

      116

      117

      118

      119

      120

      121

      122

      發現程序出現了兩個問題:

      相同的票數, 比如 5 這張票被賣了兩回

      不存在的票, 比如 0 票與 -1, 是不存在的

      這種問題, 幾個窗口 (線程)票數不同了, 這種問題成為線程不安全.

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

      線程同步

      當我們使用多個線程訪問同一資源的時候, 且多個線程中對資源有寫的操作, 就容易出現線程安全問題.

      要解決上述多線程并發訪問一個資源的安全性問題. 也就是解決重復票與不存在票問題. Java 中提供了 (synchronized) 來解決.

      根據案例描述:

      窗口 1 線程進入操作的時候, 窗口 2 和窗口 3

      線程只能在外等著. 窗口 1 操作結束, 窗口 1 和窗口 3有機會去執行. 也就是說在某個線程修改共享資源的時候, 其他線程不能去修改該資源, 等待修改完畢同步之后,才能去搶奪 CPU 資源, 完成對應的操作, 保證了數據的同步性, 解決了線程不安全的現象.

      為了保證每個線程都能正常秩序原子操作 Java 引入了線程同步機制.

      那么怎么去使用呢? 有三種方式完成同步操作:

      同步代碼塊

      同步方法

      鎖機制

      同步代碼塊

      同步代碼塊: synchronized 關鍵字可以用于方法中的某個區塊中. 表示只對這個區塊的資源實行互斥訪問.

      格式

      synchronized(同步鎖){ 需要同步操作的代碼 }

      1

      2

      3

      同步鎖

      對象的同步鎖只是一個概念, 可以想象為在對象上標記了一個鎖:

      鎖對象, 可也是任意類型

      多個線程對象, 要使用同一把鎖

      注: 在任何時候, 最多允許一個線程擁有同步鎖. 誰拿到所就進入代碼塊. 其他的線程只能在外面等著. (Blocked)

      使用同步代碼塊解決代碼:

      public class Ticket implements Runnable { private int ticket = 100; Object lock = new Object(); /** * 執行賣票操作 */ @Override public void run() { // 每個窗口賣票的操作 // 窗口, 永遠開啟 while (true) { synchronized (lock) { if (ticket > 0) { // 有票可賣 // 出票操作 // 使用sleep模擬一下出票時間 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // 獲取當前線程對象的名字 String name = Thread.currentThread().getName(); System.out.println(name + "正在賣: " + ticket--); } } } } }

      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

      27

      28

      29

      30

      當使用了同步代碼塊后, 上述的線程的安全問題, 解決了.

      同步方法

      同步方法: 使用 synchronized 修飾的方法, 就叫做同步方法. 保證 A 線程執行該方法的時候, 其他線程只能在方法外等著.

      格式

      public synchronized void method(){ 可能會產生線程安全問題的代碼 }

      1

      2

      3

      同步鎖是誰?

      對于非 static 方法, 同步鎖就是 this. 對于 static 方法, 我們使用當前方法所在類的字節碼對象 (類名.class)

      代碼

      public class Ticket implements Runnable { private int ticket = 100; /** * 執行賣票操作 */ @Override public void run() { // 每個窗口賣票的操作 // 窗口永遠開啟 while (true){ } } /** * 鎖對象是誰調用這個方法就是誰 * 隱含鎖對象就是this */ public synchronized void sellTicket(){ if(ticket > 0){ // 有票可以賣 // 出票操作 // 使用sleep模擬一下出票時間 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // 獲取當前線程對象的名字 String name = Thread.currentThread().getName(); System.out.println(name + "正在賣: " + ticket--); } } }

      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

      27

      28

      29

      30

      31

      32

      33

      34

      Lock 鎖

      java.util.concurrent.locks.Lock機制提供了比 synchronized 代碼塊和 synchronized 方法更廣泛的鎖定操作, 同步代碼塊 / 同步方法具有功能 Lock 都有, 除此之外更強大, 更體現面向對象.

      Lock 鎖也稱為同步鎖, 加鎖與釋放鎖方法如下:

      public void lock(): 加同步鎖

      public void unlock(): 釋放同步鎖

      使用如下:

      import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Ticket implements Runnable { private int ticket = 100; Lock lock = new ReentrantLock(); /** * 執行賣票操作 */ @Override public void run() { // 每個窗口賣票的操作 // 窗口永遠開啟 while (true){ lock.lock(); if(ticket > 0){ // 有票可以賣 // 出票操作 // 使用sleep模擬一下出票時間 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } // 獲取當前線程對象的名字 String name = Thread.currentThread().getName(); System.out.println(name + "正在賣: " + ticket--); } } } }

      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

      27

      28

      29

      30

      31

      Java 任務調度

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:如何在Excel中撤消/還原已刪除的工作表?
      下一篇:excel表格怎么去掉負號
      相關文章
      亚洲av无码成人精品区| 婷婷国产偷v国产偷v亚洲| 亚洲精品成人片在线播放| 欧美亚洲国产SUV| 亚洲色图.com| 亚洲AV无码一区二区三区性色 | 久久国产亚洲电影天堂| 一本色道久久综合亚洲精品蜜桃冫| 亚洲黄色网址在线观看| 国产精品xxxx国产喷水亚洲国产精品无码久久一区| 亚洲最大成人网色香蕉| 亚洲成在人线aⅴ免费毛片| 亚洲一区二区高清| 在线亚洲午夜理论AV大片| 亚洲今日精彩视频| 亚洲精品无码专区在线| 久久久久亚洲AV无码专区网站| 亚洲最大av资源站无码av网址| 久久久久亚洲AV无码专区首| 亚洲人成在线播放网站岛国| 国产国拍亚洲精品福利| 亚洲男人天堂2017| 亚洲不卡影院午夜在线观看| 亚洲精品字幕在线观看| 亚洲人成网站在线观看青青| 精品亚洲国产成人av| 久久久久亚洲精品中文字幕| 亚洲午夜国产精品| 亚洲第一精品电影网| 国产亚洲美女精品久久久| 久久久久亚洲av无码尤物| 国产亚洲人成在线影院| 中文字幕无码精品亚洲资源网久久| 亚洲高清最新av网站| 国产A在亚洲线播放| 亚洲日韩乱码久久久久久| 涩涩色中文综合亚洲| 无码久久精品国产亚洲Av影片| 最新国产精品亚洲| 在线观看亚洲人成网站| 国产成人亚洲精品无码AV大片|