Java 多線程與高并發

      網友投稿 622 2025-04-01

      保證線程可見性

      當多個線程訪問同一個共享資源時,線程會拷貝資源的副本到自己的工作內存。這樣如果某個線程對這個資源進行寫操作,其他線程不會馬上知道。當對這個資源加volatile關鍵字,其他線程就會隨時監聽,更新新的值。

      如下例子,不加volatile關鍵字,線程不會停止,加volatile關鍵字后會及時重新更新副本stop的值,線程停止。

      package com.nobody.thread; /** * 不加volatile,輸出: * main start... * thread start... * change stop=true * * 加volatile,輸出: * main start... * thread start... * thread stop... * change stop=true * @author Μr.ηobοdy * * @date 2020-04-19 * */ public class VolatileDemo { private /* volatile */ static boolean stop = false; public static void main(String[] args) { Thread t = new Thread(() -> { System.out.println("thread start..."); while (!stop) { } System.out.println("thread stop..."); }); System.out.println("main start..."); t.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } stop = true; System.out.println("change stop=" + stop); } }

      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

      禁止指令重排序

      JIT(即時編譯器just-in-time compiler) 是一種提高程序運行效率的方法,會將指令重排序。例如實例化一個對象,一般可分為3步驟,第一分配內存空間,第二初始化變量等,第三將引用地址賦值給引用對象。指令重排序可將順序改為132。這樣引用對象可能就拿到一個未初始化的對象,導致出錯。

      package com.nobody.thread; /** * 單例模式(懶漢式) * 懶漢式必須加volatile * * @author Μr.ηobοdy * * @date 2020-04-19 * */ public class Singleton { private /* vovalite */ static Singleton INSTANCE; private String name; private Singleton(String name) { this.name = name; } public static Singleton getInstance() { if (null == INSTANCE) { synchronized (Singleton.class) { if (null == INSTANCE) { // 可能會出現指令重排序,即未進行成員變量name的初始化就退出了, // 這樣別人就會拿到未初始化(name=null)的Singleton對象 INSTANCE = new Singleton("hh"); } } } return INSTANCE; } public String getName() { return name; } public void setName(String name) { this.name = name; } }

      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

      不保證原子性

      package com.nobody.thread; import java.util.ArrayList; import java.util.List; /** * volatile不保證原子性,最終結果一般小于10000 * * 若要保證原子性,直接將doCount方法加synchronized關鍵字即可,而volatile可有可無 * * @author Μr.ηobοdy * * @date 2020-04-19 * */ public class VolatileDemo1 { private volatile static int count = 0; private /*synchronized*/ void doCount() { for (int i = 0; i < 1000; i++) { count++; } } public static void main(String[] args) { VolatileDemo1 v = new VolatileDemo1(); // 啟動10個線程 List threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(v::doCount, "thread-" + i)); } threads.forEach(t -> t.start()); // 等待10個線程執行完 threads.forEach(t -> { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); System.out.println("count=" + count); } }

      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

      設置新值之前會先將舊的值與期望值比較,如果相等才set,不然就重試或者失敗。這是有CPU原語支持的。

      package com.nobody.thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * CAS AtomicInteger保證原子性,最終結果一定等于10000 * * * @author Μr.ηobοdy * * @date 2020-04-19 * */ public class AtomicIntegerDemo { private static AtomicInteger count = new AtomicInteger(0); private void doCount() { for (int i = 0; i < 1000; i++) { count.incrementAndGet(); } } public static void main(String[] args) { AtomicIntegerDemo v = new AtomicIntegerDemo(); // 啟動10個線程 List threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(v::doCount, "thread-" + i)); } threads.forEach(t -> t.start()); // 等待10個線程執行完 threads.forEach(t -> { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); System.out.println("count=" + count); } }

      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

      不過這種會出現ABA問題,即由值A先變成值B,然后又變回A值,最后舊值與期望值比較還是相等。可用版本號解決這個問題。

      采用分段鎖思想,假如有1000個線程對同一個共享變量進行操作(例如自增),此處假設分為4小組,250個線程為1組,組內進行自增操作,這樣分組能減少鎖的概率,最后將每個小組進行求總和處理。其實分段鎖組內還是CAS原理。一般在線程數高時,效率比synchronized和AtomicLong高。

      package com.nobody.thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.LongAdder; /** * LongAdder,AtomicLong,synchronized多線程時效率比較 * 模擬1000個線程對一個等于0的值進行自增操作,每個線程自增10000 * * 輸出結果: * longAdderCount:10000000, time:227 * atomicLongCount:10000000, time:395 * synchronizedCount:10000000, time:909 * * @author Μr.ηobοdy * * @date 2020-04-20 * */ public class LongAdderDemo { private static LongAdder longAdderCount = new LongAdder(); private static AtomicLong atomicLongCount = new AtomicLong(0L); private static long synchronizedCount = 0L; public static void main(String[] args) { // LongAdder測試 List longAdderThreads = new ArrayList<>(1000); for (int i = 1; i <= 1000; i++) { longAdderThreads.add(new Thread(() -> { for (int j = 0; j < 10000; j++) { longAdderCount.increment(); } })); } long start = System.currentTimeMillis(); longAdderThreads.forEach(t -> t.start()); // 等待1000個線程執行完 longAdderThreads.forEach(t -> { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); long end = System.currentTimeMillis(); // AtomicLong測試 List atomicLongThreads = new ArrayList<>(1000); for (int i = 1; i <= 1000; i++) { atomicLongThreads.add(new Thread(() -> { for (int j = 0; j < 10000; j++) { atomicLongCount.incrementAndGet(); } })); } long start1 = System.currentTimeMillis(); atomicLongThreads.forEach(t -> t.start()); // 等待1000個線程執行完 atomicLongThreads.forEach(t -> { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); long end1 = System.currentTimeMillis(); // AtomicLong測試 List synchronizedThreads = new ArrayList<>(1000); Object o = new Object(); for (int i = 1; i <= 1000; i++) { synchronizedThreads.add(new Thread(() -> { for (int j = 0; j < 10000; j++) { synchronized (o) { synchronizedCount++; } } })); } long start2 = System.currentTimeMillis(); synchronizedThreads.forEach(t -> t.start()); // 等待1000個線程執行完 synchronizedThreads.forEach(t -> { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); long end2 = System.currentTimeMillis(); System.out.println("longAdderCount:" + longAdderCount + ", time:" + (end - start)); System.out.println("atomicLongCount:" + atomicLongCount + ", time:" + (end1 - start1)); System.out.println("synchronizedCount:" + synchronizedCount + ", time:" + (end2 - start2)); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      Java 多線程與高并發

      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

      Java 任務調度 多線程

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

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

      上一篇:怎么把兩份表格合并在一個工作本上(兩個工作表格怎么合并到一起)
      下一篇:在Excel表格中如何改變表格顏色?(excel表格里怎么改顏色)
      相關文章
      麻豆亚洲AV永久无码精品久久 | 国产亚洲精品精品国产亚洲综合| 亚洲不卡1卡2卡三卡2021麻豆| 亚洲精品电影天堂网| 中文字幕亚洲综合久久2| 亚洲精品中文字幕无码蜜桃| 亚洲中文字幕无码一区二区三区| 337p日本欧洲亚洲大胆裸体艺术| 亚洲av区一区二区三| 亚洲不卡AV影片在线播放| 亚洲高清无码综合性爱视频| 亚洲国产精品自产在线播放| 亚洲性久久久影院| 亚洲无码黄色网址| 国产亚洲精品无码拍拍拍色欲| 亚洲欭美日韩颜射在线二| 亚洲热线99精品视频| 亚洲成av人在线视| 亚洲∧v久久久无码精品| 亚洲综合无码一区二区| 亚洲成A∨人片在线观看无码| 亚洲一区二区三区在线| 色老板亚洲视频免在线观| 亚洲一区二区三区高清在线观看 | 久久国产亚洲精品麻豆| 久久亚洲精品成人综合| 久久精品国产亚洲AV无码偷窥| 亚洲福利视频一区二区三区| 亚洲人成在久久综合网站| 亚洲性色精品一区二区在线| 色天使色婷婷在线影院亚洲| 亚洲乱码日产精品a级毛片久久| 国产日产亚洲系列| 亚洲av日韩av无码黑人| 亚洲自偷自拍另类图片二区| 亚洲天堂2016| 国产精品亚洲va在线观看| 国产乱辈通伦影片在线播放亚洲 | 亚洲av高清在线观看一区二区| 亚洲熟妇av一区二区三区| 亚洲AV区无码字幕中文色|