Java線程之間通信的幾種方式詳解
1. 共享變量與同步機(jī)制
多個(gè)線程可以通過(guò)共享對(duì)象的變量進(jìn)行通信,但為了避免數(shù)據(jù)不一致的問(wèn)題,必須使用同步機(jī)制來(lái)控制對(duì)共享變量的訪問(wèn)。
使用
synchronized關(guān)鍵字:synchronized確保在同一時(shí)刻只有一個(gè)線程可以執(zhí)行同步代碼塊。它可以同步方法或代碼塊,用于保護(hù)共享數(shù)據(jù)。示例:
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
public class SyncExample {
public static void main(String[] args) {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + counter.getCount());
}
}使用場(chǎng)景:用于保護(hù)共享資源,防止多個(gè)線程同時(shí)讀寫導(dǎo)致數(shù)據(jù)不一致的問(wèn)題。
使用
volatile關(guān)鍵字:volatile確保一個(gè)線程對(duì)變量的修改對(duì)其他線程立即可見(jiàn)。它適用于輕量級(jí)的變量同步,通常用于標(biāo)志位控制。示例:
class Flag {
private volatile boolean running = true;
public void stop() {
running = false;
}
public boolean isRunning() {
return running;
}
}
public class VolatileExample {
public static void main(String[] args) {
Flag flag = new Flag();
Thread t1 = new Thread(() -> {
while (flag.isRunning()) {
System.out.println("Thread is running");
}
System.out.println("Thread stopped");
});
t1.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag.stop();
}
}使用場(chǎng)景:用于控制線程的退出、開關(guān)操作等輕量級(jí)場(chǎng)景。
2. wait()、notify() 和 notifyAll()
Object 類的這三個(gè)方法用于在同步塊內(nèi)實(shí)現(xiàn)線程間的協(xié)作。線程可以通過(guò) wait() 進(jìn)入等待狀態(tài),直到另一個(gè)線程調(diào)用 notify() 或 notifyAll() 喚醒它們。
wait():當(dāng)前線程進(jìn)入等待狀態(tài),并釋放鎖。notify():?jiǎn)拘岩粋€(gè)正在等待同一鎖的線程。notifyAll():?jiǎn)拘阉械却绘i的線程。
示例:生產(chǎn)者-消費(fèi)者模型
class SharedResource {
private int value;
private boolean hasValue = false;
public synchronized void produce(int newValue) throws InterruptedException {
while (hasValue) {
wait(); // 等待消費(fèi)者消費(fèi)
}
value = newValue;
hasValue = true;
System.out.println("Produced: " + value);
notify(); // 喚醒消費(fèi)者
}
public synchronized void consume() throws InterruptedException {
while (!hasValue) {
wait(); // 等待生產(chǎn)者生產(chǎn)
}
System.out.println("Consumed: " + value);
hasValue = false;
notify(); // 喚醒生產(chǎn)者
}
}
public class ProducerConsumerExample {
public static void main(String[] args) {
SharedResource resource = new SharedResource();
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
resource.produce(i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
resource.consume();
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
}
}使用場(chǎng)景:適用于線程間的協(xié)調(diào)工作,比如生產(chǎn)者-消費(fèi)者模型,一個(gè)線程負(fù)責(zé)生產(chǎn)資源,另一個(gè)線程負(fù)責(zé)消費(fèi)資源。
3. Lock 和 Condition 接口
相比 synchronized,Lock 提供了更靈活的同步機(jī)制,而 Condition 可以替代 wait()、notify() 和 notifyAll(),并支持多個(gè)等待條件。
ReentrantLock:常用于顯式鎖控制,可以提供公平鎖機(jī)制(按獲取鎖的順序進(jìn)行調(diào)度)。Condition:類似于Object的wait()、notify(),可以創(chuàng)建多個(gè)Condition來(lái)進(jìn)行復(fù)雜的線程協(xié)調(diào)。
示例:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class BoundedBuffer {
private final int[] buffer;
private int count, in, out;
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
public BoundedBuffer(int size) {
buffer = new int[size];
}
public void put(int value) throws InterruptedException {
lock.lock();
try {
while (count == buffer.length) {
notFull.await(); // 等待緩沖區(qū)未滿
}
buffer[in] = value;
in = (in + 1) % buffer.length;
count++;
notEmpty.signal(); // 喚醒消費(fèi)線程
} finally {
lock.unlock();
}
}
public int take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
notEmpty.await(); // 等待緩沖區(qū)非空
}
int value = buffer[out];
out = (out + 1) % buffer.length;
count--;
notFull.signal(); // 喚醒生產(chǎn)線程
return value;
} finally {
lock.unlock();
}
}
}
public class LockConditionExample {
public static void main(String[] args) {
BoundedBuffer buffer = new BoundedBuffer(5);
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
buffer.put(i);
System.out.println("Produced: " + i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
int value = buffer.take();
System.out.println("Consumed: " + value);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
producer.start();
consumer.start();
}
}使用場(chǎng)景:適用于需要顯式鎖定、更復(fù)雜的條件等待場(chǎng)景,比如多條件同步、多生產(chǎn)者-消費(fèi)者模型。
4. java.util.concurrent 包的并發(fā)工具
Java 提供了 java.util.concurrent 包下的一系列高級(jí)并發(fā)工具類來(lái)簡(jiǎn)化線程間通信。
- BlockingQueue:線程安全的隊(duì)列,常用于生產(chǎn)者-消費(fèi)者模式。
- CountDownLatch:允許一個(gè)或多個(gè)線程等待其他線程完成某些操作。
- CyclicBarrier:多個(gè)線程在某個(gè)點(diǎn)上相互等待,直到所有線程到達(dá)該點(diǎn)。
- Semaphore:用于控制對(duì)資源的訪問(wèn)許可。
- Exchanger:用于兩個(gè)線程之間交換數(shù)據(jù)。
到此這篇關(guān)于Java線程之間通信的幾種方式詳解的文章就介紹到這了,更多相關(guān)Java線程之間通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java時(shí)間戳與日期相互轉(zhuǎn)換工具詳解
這篇文章主要為大家詳細(xì)介紹了java各種時(shí)間戳與日期之間相互轉(zhuǎn)換的工具,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
MyBatis-Plus多表關(guān)聯(lián)分頁(yè)方式
文章介紹了使用MyBatis-Plus的QueryWrapper進(jìn)行多表關(guān)聯(lián)查詢的方法,通過(guò)select()方法定義需要的字段,將ID字段轉(zhuǎn)化為名稱字段,實(shí)現(xiàn)一次查詢,這種方法簡(jiǎn)單便捷,但在使用where語(yǔ)句查詢子表字段時(shí)有一定限制,作者建議建立數(shù)據(jù)庫(kù)視圖表作為更好的解決方案2026-05-05
Jmeter的接口測(cè)試詳細(xì)步驟并實(shí)現(xiàn)業(yè)務(wù)閉環(huán)
這篇文章主要介紹了Jmeter的接口測(cè)試詳細(xì)步驟并實(shí)現(xiàn)業(yè)務(wù)閉環(huán),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08
spring啟動(dòng)后保證創(chuàng)建的對(duì)象不被垃圾回收器回收
最近看到一個(gè)問(wèn)題是,spring在啟動(dòng)后如何保證創(chuàng)建的對(duì)象不被垃圾回收器回收?。所以本文結(jié)合jvm的垃圾回收機(jī)制和spring中的源代碼做出自己的一點(diǎn)猜測(cè)。有需要的朋友們可以參考借鑒。2016-09-09
Java多線程實(shí)現(xiàn)之Callable詳解
這篇文章主要介紹了Java多線程實(shí)現(xiàn)之Callable詳解,Callable是一個(gè)接口,用于實(shí)現(xiàn)多線程,與實(shí)現(xiàn)Runnable類似,但是功能更強(qiáng)大,通過(guò)實(shí)現(xiàn)Callable接口,我們需要重寫call()方法,該方法可以在任務(wù)結(jié)束后提供一個(gè)返回值,需要的朋友可以參考下2023-08-08
springboot websocket簡(jiǎn)單入門示例
這篇文章主要介紹了springboot websocket簡(jiǎn)單入門示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
Springboot 全局時(shí)間格式化三種方式示例詳解
時(shí)間格式化在項(xiàng)目中使用頻率是非常高的,當(dāng)我們的 API? 接口返回結(jié)果,需要對(duì)其中某一個(gè) date? 字段屬性進(jìn)行特殊的格式化處理,通常會(huì)用到 SimpleDateFormat? 工具處理,這篇文章主要介紹了3 種 Springboot 全局時(shí)間格式化方式,需要的朋友可以參考下2024-01-01

