Java線程之間通信的幾種方式詳解
1. 共享變量與同步機制
多個線程可以通過共享對象的變量進行通信,但為了避免數據不一致的問題,必須使用同步機制來控制對共享變量的訪問。
使用
synchronized關鍵字:synchronized確保在同一時刻只有一個線程可以執(zhí)行同步代碼塊。它可以同步方法或代碼塊,用于保護共享數據。示例:
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());
}
}使用場景:用于保護共享資源,防止多個線程同時讀寫導致數據不一致的問題。
使用
volatile關鍵字:volatile確保一個線程對變量的修改對其他線程立即可見。它適用于輕量級的變量同步,通常用于標志位控制。示例:
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();
}
}使用場景:用于控制線程的退出、開關操作等輕量級場景。
2. wait()、notify() 和 notifyAll()
Object 類的這三個方法用于在同步塊內實現(xiàn)線程間的協(xié)作。線程可以通過 wait() 進入等待狀態(tài),直到另一個線程調用 notify() 或 notifyAll() 喚醒它們。
wait():當前線程進入等待狀態(tài),并釋放鎖。notify():喚醒一個正在等待同一鎖的線程。notifyAll():喚醒所有等待同一鎖的線程。
示例:生產者-消費者模型
class SharedResource {
private int value;
private boolean hasValue = false;
public synchronized void produce(int newValue) throws InterruptedException {
while (hasValue) {
wait(); // 等待消費者消費
}
value = newValue;
hasValue = true;
System.out.println("Produced: " + value);
notify(); // 喚醒消費者
}
public synchronized void consume() throws InterruptedException {
while (!hasValue) {
wait(); // 等待生產者生產
}
System.out.println("Consumed: " + value);
hasValue = false;
notify(); // 喚醒生產者
}
}
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();
}
}使用場景:適用于線程間的協(xié)調工作,比如生產者-消費者模型,一個線程負責生產資源,另一個線程負責消費資源。
3. Lock 和 Condition 接口
相比 synchronized,Lock 提供了更靈活的同步機制,而 Condition 可以替代 wait()、notify() 和 notifyAll(),并支持多個等待條件。
ReentrantLock:常用于顯式鎖控制,可以提供公平鎖機制(按獲取鎖的順序進行調度)。Condition:類似于Object的wait()、notify(),可以創(chuàng)建多個Condition來進行復雜的線程協(xié)調。
示例:
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(); // 喚醒消費線程
} 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(); // 喚醒生產線程
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();
}
}使用場景:適用于需要顯式鎖定、更復雜的條件等待場景,比如多條件同步、多生產者-消費者模型。
4. java.util.concurrent 包的并發(fā)工具
Java 提供了 java.util.concurrent 包下的一系列高級并發(fā)工具類來簡化線程間通信。
- BlockingQueue:線程安全的隊列,常用于生產者-消費者模式。
- CountDownLatch:允許一個或多個線程等待其他線程完成某些操作。
- CyclicBarrier:多個線程在某個點上相互等待,直到所有線程到達該點。
- Semaphore:用于控制對資源的訪問許可。
- Exchanger:用于兩個線程之間交換數據。
到此這篇關于Java線程之間通信的幾種方式詳解的文章就介紹到這了,更多相關Java線程之間通信內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
聊聊Spring AOP @Before @Around @After等advice的執(zhí)行順序
這篇文章主要介紹了聊聊Spring AOP @Before @Around @After等advice的執(zhí)行順序,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Thread類interrupt interrupted及isInterrupted區(qū)別
這篇文章主要為大家介紹了Thread類interrupt interrupted及isInterrupted區(qū)別,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-10-10
Spring @Async無法實現(xiàn)異步的解決方案
這篇文章主要介紹了Spring @Async無法實現(xiàn)異步的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10

