成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試突擊:線程安全問題的解決方案有哪些?

開發 前端
使用 ThreadLocal 線程本地變量也可以解決線程安全問題,它是給每個線程獨自創建了一份屬于自己的私有變量,不同的線程操作的是不同的變量,所以也不會存在非線程安全的問題,

線程安全是指某個方法或某段代碼,在多線程中能夠正確的執行,不會出現數據不一致或數據污染的情況,我們把這樣的程序稱之為線程安全的,反之則為非線程安全的。在 Java 中,解決線程安全問題有以下 3 種手段:

  • 使用線程安全類,比如 AtomicInteger。
  • 加鎖排隊執行

使用 synchronized 加鎖。

使用 ReentrantLock 加鎖。

  • 使用線程本地變量 ThreadLocal。

接下來我們逐個來看它們的實現。

線程安全問題

演示我們創建一個變量 number 等于 0,之后創建線程 1,執行 100 萬次 ++ 操作,同時再創建線程 2 執行 100 萬次 -- 操作,等線程 1 和線程 2 都執行完之后,打印 number 變量的值,如果打印的結果為 0,則說明是線程安全的,否則則為非線程安全的,示例代碼如下:

public class ThreadSafeTest {
// 全局變量
private static int number = 0;
// 循環次數(100W)
private static final int COUNT = 1_000_000;

public static void main(String[] args) throws InterruptedException {
// 線程1:執行 100W 次 ++ 操作
Thread t1 = new Thread(() -> {
for (int i = 0; i < COUNT; i++) {
number++;
}
});
t1.start();

// 線程2:執行 100W 次 -- 操作
Thread t2 = new Thread(() -> {
for (int i = 0; i < COUNT; i++) {
number--;
}
});
t2.start();

// 等待線程 1 和線程 2,執行完,打印 number 最終的結果
t1.join();
t2.join();
System.out.println("number 最終結果:" + number);
}
}

以上程序的執行結果如下圖所示:

從上述執行結果可以看出,number 變量最終的結果并不是 0,和預期的正確結果不相符,這就是多線程中的線程安全問題。

解決線程安全問題

1.原子類AtomicIntege

AtomicInteger 是線程安全的類,使用它可以將 ++ 操作和 -- 操作,變成一個原子性操作,這樣就能解決非線程安全的問題了,如下代碼所示:

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerExample {
// 創建 AtomicInteger
private static AtomicInteger number = new AtomicInteger(0);
// 循環次數
private static final int COUNT = 1_000_000;

public static void main(String[] args) throws InterruptedException {
// 線程1:執行 100W 次 ++ 操作
Thread t1 = new Thread(() -> {
for (int i = 0; i < COUNT; i++) {
// ++ 操作
number.incrementAndGet();
}
});
t1.start();

// 線程2:執行 100W 次 -- 操作
Thread t2 = new Thread(() -> {
for (int i = 0; i < COUNT; i++) {
// -- 操作
number.decrementAndGet();
}
});
t2.start();

// 等待線程 1 和線程 2,執行完,打印 number 最終的結果
t1.join();
t2.join();
System.out.println("最終結果:" + number.get());
}
}

以上程序的執行結果如下圖所示:

2.加鎖排隊執行

Java 中有兩種鎖:synchronized 同步鎖和 ReentrantLock 可重入鎖。

2.1 同步鎖synchronized

synchronized 是 JVM 層面實現的自動加鎖和自動釋放鎖的同步鎖,它的實現代碼如下:

public class SynchronizedExample {
// 全局變量
private static int number = 0;
// 循環次數(100W)
private static final int COUNT = 1_000_000;

public static void main(String[] args) throws InterruptedException {
// 線程1:執行 100W 次 ++ 操作
Thread t1 = new Thread(() -> {
for (int i = 0; i < COUNT; i++) {
// 加鎖排隊執行
synchronized (SynchronizedExample.class) {
number++;
}
}
});
t1.start();

// 線程2:執行 100W 次 -- 操作
Thread t2 = new Thread(() -> {
for (int i = 0; i < COUNT; i++) {
// 加鎖排隊執行
synchronized (SynchronizedExample.class) {
number--;
}
}
});
t2.start();

// 等待線程 1 和線程 2,執行完,打印 number 最終的結果
t1.join();
t2.join();
System.out.println("number 最終結果:" + number);
}
}

以上程序的執行結果如下圖所示:

2.2 可重入鎖ReentrantLock

ReentrantLock 可重入鎖需要程序員自己加鎖和釋放鎖,它的實現代碼如下:

import java.util.concurrent.locks.ReentrantLock;

/**
* 使用 ReentrantLock 解決非線程安全問題
*/
public class ReentrantLockExample {
// 全局變量
private static int number = 0;
// 循環次數(100W)
private static final int COUNT = 1_000_000;
// 創建 ReentrantLock
private static ReentrantLock lock = new ReentrantLock();

public static void main(String[] args) throws InterruptedException {
// 線程1:執行 100W 次 ++ 操作
Thread t1 = new Thread(() -> {
for (int i = 0; i < COUNT; i++) {
lock.lock(); // 手動加鎖
number++; // ++ 操作
lock.unlock(); // 手動釋放鎖
}
});
t1.start();

// 線程2:執行 100W 次 -- 操作
Thread t2 = new Thread(() -> {
for (int i = 0; i < COUNT; i++) {
lock.lock(); // 手動加鎖
number--; // -- 操作
lock.unlock(); // 手動釋放鎖
}
});
t2.start();

// 等待線程 1 和線程 2,執行完,打印 number 最終的結果
t1.join();
t2.join();
System.out.println("number 最終結果:" + number);
}
}

以上程序的執行結果如下圖所示:

3.線程本地變量ThreadLocal

使用 ThreadLocal 線程本地變量也可以解決線程安全問題,它是給每個線程獨自創建了一份屬于自己的私有變量,不同的線程操作的是不同的變量,所以也不會存在非線程安全的問題,它的實現代碼如下:

public class ThreadSafeExample {
// 創建 ThreadLocal(設置每個線程中的初始值為 0)
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);
// 全局變量
private static int number = 0;
// 循環次數(100W)
private static final int COUNT = 1_000_000;

public static void main(String[] args) throws InterruptedException {
// 線程1:執行 100W 次 ++ 操作
Thread t1 = new Thread(() -> {
try {
for (int i = 0; i < COUNT; i++) {
// ++ 操作
threadLocal.set(threadLocal.get() + 1);
}
// 將 ThreadLocal 中的值進行累加
number += threadLocal.get();
} finally {
threadLocal.remove(); // 清除資源,防止內存溢出
}
});
t1.start();

// 線程2:執行 100W 次 -- 操作
Thread t2 = new Thread(() -> {
try {
for (int i = 0; i < COUNT; i++) {
// -- 操作
threadLocal.set(threadLocal.get() - 1);
}
// 將 ThreadLocal 中的值進行累加
number += threadLocal.get();
} finally {
threadLocal.remove(); // 清除資源,防止內存溢出
}
});
t2.start();

// 等待線程 1 和線程 2,執行完,打印 number 最終的結果
t1.join();
t2.join();
System.out.println("最終結果:" + number);
}
}

以上程序的執行結果如下圖所示:

總結

在 Java 中,解決線程安全問題的手段有 3 種:

1.使用線程安全的類,如 AtomicInteger 類;

2.使用鎖 synchronized 或 ReentrantLock 加鎖排隊執行;

3.使用線程本地變量 ThreadLocal 來處理。

責任編輯:武曉燕 來源: Java面試真題解析
相關推薦

2022-04-06 07:50:28

線程安全代碼

2019-04-02 08:20:37

2023-03-24 15:06:03

2023-02-28 07:40:09

編譯器Java線程安全

2019-06-14 05:00:05

2009-11-12 15:05:13

USB移動安全解決方案

2009-07-13 10:36:18

2009-10-28 11:27:49

linux服務器安全

2024-09-26 00:00:10

死鎖阿里面試

2024-09-17 17:50:28

線程線程安全代碼

2020-04-10 08:34:58

網絡安全郵件安全網絡釣魚

2022-05-11 07:41:55

死鎖運算線程

2022-03-23 08:51:21

線程池Java面試題

2022-04-18 07:36:37

TimeUnit線程休眠

2022-06-06 07:35:26

MySQLInnoDBMyISAM

2022-01-24 07:01:20

安全多線程版本

2022-06-01 12:00:54

HTTP狀態碼服務端

2024-11-14 14:53:04

2023-12-17 14:19:57

2020-03-11 09:57:10

數據安全網絡安全網絡攻擊
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩不卡视频在线观看 | 四虎在线观看 | 色综合色综合网色综合 | 一级片免费在线观看 | 午夜精品一区二区三区在线视频 | 在线a视频网站 | 欧美一级二级三级视频 | 久久99精品国产 | 狠狠久久 | 天天精品在线 | 日韩一区二区三区在线观看 | 91玖玖| 亚洲不卡av在线 | 日韩中文一区二区 | 99久久国产 | 国产羞羞视频在线观看 | 欧美专区在线 | 啪啪免费 | 欧美日韩国产在线观看 | 亚洲成人一区 | 国产91丝袜 | 日韩免费网站 | 亚洲综合色网站 | 97视频网站 | 亚洲精品久久区二区三区蜜桃臀 | 成人av电影天堂 | 精品国产免费人成在线观看 | 99久久久久久久 | 在线三级网址 | 午夜免费看 | 久久久久久久久淑女av国产精品 | 成人精品视频 | 久久精品国产久精国产 | 亚洲九九色| 精品在线一区 | 免费在线观看91 | 国内av在线 | 亚洲欧美激情精品一区二区 | 欧洲精品码一区二区三区免费看 | 国产精品视频在线播放 | jizz视频 |