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í)讀寫(xiě)導(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)景:用于控制線程的退出、開(kāi)關(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)文章
聊聊Spring AOP @Before @Around @After等advice的執(zhí)行順序
這篇文章主要介紹了聊聊Spring AOP @Before @Around @After等advice的執(zhí)行順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02Thread類interrupt interrupted及isInterrupted區(qū)別
這篇文章主要為大家介紹了Thread類interrupt interrupted及isInterrupted區(qū)別,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Spring @Async無(wú)法實(shí)現(xiàn)異步的解決方案
這篇文章主要介紹了Spring @Async無(wú)法實(shí)現(xiàn)異步的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10SpringBoot之Order注解啟動(dòng)順序說(shuō)明
這篇文章主要介紹了SpringBoot之Order注解啟動(dòng)順序說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09Java中的對(duì)象和對(duì)象引用實(shí)例淺析
這篇文章主要介紹了Java中的對(duì)象和對(duì)象引用,實(shí)例分析了對(duì)象與對(duì)象引用的概念與相關(guān)使用技巧,需要的朋友可以參考下2015-05-05簡(jiǎn)單實(shí)現(xiàn)java抽獎(jiǎng)系統(tǒng)
這篇文章主要教大家如何簡(jiǎn)單實(shí)現(xiàn)java抽獎(jiǎng)系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01