Java 中使用同步線程的多種實(shí)現(xiàn)方式
1. 前序
在多線程編程中,線程同步是確保數(shù)據(jù)一致性和防止競(jìng)態(tài)條件的關(guān)鍵。Java 提供了多種用于線程同步的機(jī)制,以解決不同場(chǎng)景下的線程競(jìng)爭(zhēng)問(wèn)題。無(wú)論是最基本的 synchronized? 關(guān)鍵字,還是更靈活的 ReentrantLock?、ReentrantReadWriteLock?,它們都為開(kāi)發(fā)者提供了不同級(jí)別的鎖和控制。
本文將逐一介紹 Java 中常見(jiàn)的同步機(jī)制,涵蓋了 synchronized?、ReentrantLock?、Atomic? 類(lèi)等,同時(shí)給出每種機(jī)制的示例代碼和適用場(chǎng)景,幫助你更好地理解并應(yīng)用這些同步機(jī)制。
2.synchronized?
2.1synchronized? 關(guān)鍵字
- 描述:Java 中最基礎(chǔ)的同步機(jī)制就是
synchronized? 關(guān)鍵字,它可以用于方法或代碼塊,確保同一時(shí)刻只有一個(gè)線程可以訪問(wèn)共享資源。 - 示例代碼:
/**
* 示例類(lèi),演示如何使用 synchronized 方法進(jìn)行線程同步
*/
public class SynchronizedMethodExample {
/** 共享計(jì)數(shù)器 */
private int counter = 0;
/**
* 同步遞增計(jì)數(shù)器的方法,確保同一時(shí)刻只有一個(gè)線程可以執(zhí)行
*/
public synchronized void increment() {
// 遞增計(jì)數(shù)器
counter++;
// 輸出當(dāng)前線程和計(jì)數(shù)器的值
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
}
/**
* 主程序入口,創(chuàng)建多個(gè)線程并運(yùn)行
* @param args 默認(rèn)參數(shù)
*/
public static void main(String[] args) {
SynchronizedMethodExample example = new SynchronizedMethodExample();
// 線程任務(wù),調(diào)用 increment 方法
Runnable task = example::increment;
// 創(chuàng)建兩個(gè)線程
Thread t1 = new Thread(task, "Thread 1");
Thread t2 = new Thread(task, "Thread 2");
// 啟動(dòng)線程
t1.start();
t2.start();
}
}
2.2 使用synchronized? 代碼塊
- 描述:相比于
synchronized? 方法,synchronized? 代碼塊允許更細(xì)粒度地控制同步范圍??梢灾付ㄌ囟ǖ拇a塊進(jìn)行同步,而不是整個(gè)方法,這樣可以減少鎖的競(jìng)爭(zhēng),提高效率。 - 示例代碼:
/**
* 示例類(lèi),演示如何使用 synchronized 代碼塊進(jìn)行線程同步
*/
public class SynchronizedBlockExample {
/** 共享計(jì)數(shù)器 */
private int counter = 0;
/** 自定義鎖對(duì)象 */
private final Object lock = new Object();
/**
* 同步遞增計(jì)數(shù)器的方法,只鎖定代碼塊
*/
public void increment() {
// 使用 synchronized 代碼塊確保鎖定的粒度更小
synchronized (lock) {
counter++;
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
}
}
/**
* 主程序入口,創(chuàng)建多個(gè)線程并運(yùn)行
* @param args 默認(rèn)參數(shù)
*/
public static void main(String[] args) {
SynchronizedBlockExample example = new SynchronizedBlockExample();
Runnable task = example::increment;
Thread t1 = new Thread(task, "Thread 1");
Thread t2 = new Thread(task, "Thread 2");
t1.start();
t2.start();
}
}
3.ReentrantLock?
- 描述:
ReentrantLock? 是Lock? 接口的一個(gè)常用實(shí)現(xiàn),它提供了更靈活的鎖定機(jī)制,允許手動(dòng)加鎖和解鎖。 - 示例代碼:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 示例類(lèi),演示如何使用 ReentrantLock 進(jìn)行線程同步
*/
public class LockExample {
/** 共享計(jì)數(shù)器 */
private int counter = 0;
/** ReentrantLock 實(shí)例 */
private final Lock lock = new ReentrantLock();
/**
* 同步遞增計(jì)數(shù)器的方法,手動(dòng)加鎖和解鎖
*/
public void increment() {
// 獲取鎖
lock.lock();
try {
// 遞增計(jì)數(shù)器
counter++;
// 輸出當(dāng)前線程和計(jì)數(shù)器的值
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
} finally {
// 確保鎖在最后被釋放
lock.unlock();
}
}
/**
* 主程序入口,創(chuàng)建多個(gè)線程并運(yùn)行
* @param args 默認(rèn)參數(shù)
*/
public static void main(String[] args) {
LockExample example = new LockExample();
Runnable task = example::increment;
Thread t1 = new Thread(task, "Thread 1");
Thread t2 = new Thread(task, "Thread 2");
t1.start();
t2.start();
}
}
4.ReentrantReadWriteLock?
- 描述:
ReentrantReadWriteLock? 提供了讀寫(xiě)鎖機(jī)制,可以讓多個(gè)線程并發(fā)讀取,但在寫(xiě)入時(shí)只有一個(gè)線程可以操作。這樣可以提高在讀多寫(xiě)少場(chǎng)景下的性能。 - 示例代碼:
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 示例類(lèi),演示如何使用 ReentrantReadWriteLock 進(jìn)行線程同步
*/
public class ReadWriteLockExample {
/** 共享計(jì)數(shù)器 */
private int counter = 0;
/** ReentrantReadWriteLock 實(shí)例 */
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
/**
* 獲取寫(xiě)鎖并遞增計(jì)數(shù)器
*/
public void increment() {
// 獲取寫(xiě)鎖
lock.writeLock().lock();
try {
// 遞增計(jì)數(shù)器
counter++;
System.out.println(Thread.currentThread().getName() + " - Write Counter: " + counter);
} finally {
// 釋放寫(xiě)鎖
lock.writeLock().unlock();
}
}
/**
* 獲取讀鎖并讀取計(jì)數(shù)器
* @return 計(jì)數(shù)器值
*/
public int getCounter() {
// 獲取讀鎖
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " - Read Counter: " + counter);
return counter;
} finally {
// 釋放讀鎖
lock.readLock().unlock();
}
}
/**
* 主程序入口,創(chuàng)建多個(gè)線程并運(yùn)行
* @param args 默認(rèn)參數(shù)
*/
public static void main(String[] args) {
ReadWriteLockExample example = new ReadWriteLockExample();
Runnable writeTask = example::increment;
Runnable readTask = example::getCounter;
Thread t1 = new Thread(writeTask, "Writer Thread");
Thread t2 = new Thread(readTask, "Reader Thread");
t1.start();
t2.start();
}
}
5.Atomic? 類(lèi)
- 描述:
Atomic? 類(lèi)位于java.util.concurrent.atomic? 包內(nèi),提供了常見(jiàn)的原子操作類(lèi)(如AtomicInteger?),用于在無(wú)鎖的情況下對(duì)單一變量進(jìn)行線程安全的操作。 - 示例代碼:
import java.util.concurrent.atomic.AtomicInteger;
/**
* 示例類(lèi),演示如何使用 AtomicInteger 進(jìn)行線程同步
*/
public class AtomicExample {
/** 線程安全的 AtomicInteger */
private AtomicInteger counter = new AtomicInteger(0);
/**
* 原子性遞增計(jì)數(shù)器的方法
*/
public void increment() {
// 原子遞增
int newValue = counter.incrementAndGet();
System.out.println(Thread.currentThread().getName() + " - Counter: " + newValue);
}
/**
* 主程序入口,創(chuàng)建多個(gè)線程并運(yùn)行
* @param args 默認(rèn)參數(shù)
*/
public static void main(String[] args) {
AtomicExample example = new AtomicExample();
Runnable task = example::increment;
Thread t1 = new Thread(task, "Thread 1");
Thread t2 = new Thread(task, "Thread 2");
t1.start();
t2.start();
}
}
6.CyclicBarrier?
- 描述:
CyclicBarrier? 是一種允許一組線程相互等待的同步機(jī)制,直到所有線程都到達(dá)某個(gè)共同的屏障點(diǎn)時(shí),才能繼續(xù)執(zhí)行。它支持重用,即可以被多次使用。 - 示例代碼:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 示例類(lèi),演示如何使用 CyclicBarrier 實(shí)現(xiàn)線程同步
*/
public class CyclicBarrierExample {
/** CyclicBarrier 實(shí)例,等待 3 個(gè)線程 */
private final CyclicBarrier barrier = new CyclicBarrier(3, () -> {
// 所有線程到達(dá)屏障后執(zhí)行的操作
System.out.println("All threads have reached the barrier. Barrier action executed.");
});
/**
* 線程任務(wù),等待屏障點(diǎn)并繼續(xù)執(zhí)行
*/
public void performTask() {
System.out.println(Thread.currentThread().getName() + " is waiting at the barrier");
try {
// 等待其他線程到達(dá)屏障點(diǎn)
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " has crossed the barrier");
}
/**
* 主程序入口,創(chuàng)建多個(gè)線程并運(yùn)行
* @param args 默認(rèn)參數(shù)
*/
public static void main(String[] args) {
CyclicBarrierExample example = new CyclicBarrierExample();
Thread t1 = new Thread(example::performTask, "Thread 1");
Thread t2 = new Thread(example::performTask, "Thread 2");
Thread t3 = new Thread(example::performTask, "Thread 3");
t1.start();
t2.start();
t3.start();
}
}
7.Object? 的wait()? 和notify()? 方法
- 描述:
Object? 類(lèi)的wait()?、notify()? 和notifyAll()? 方法允許線程在某個(gè)條件下進(jìn)行等待和喚醒。與synchronized? 搭配使用,可以實(shí)現(xiàn)類(lèi)似于信號(hào)量的功能。 - 示例代碼:
/**
* 示例類(lèi),演示如何使用 wait() 和 notify() 進(jìn)行線程同步
*/
public class WaitNotifyExample {
/** 自定義鎖對(duì)象 */
private final Object lock = new Object();
/** 標(biāo)志位,表示是否已經(jīng)生產(chǎn)了數(shù)據(jù) */
private boolean isProduced = false;
/**
* 生產(chǎn)者方法,等待消費(fèi)者消費(fèi)后生產(chǎn)新數(shù)據(jù)
* @throws InterruptedException 當(dāng)線程被中斷時(shí)拋出異常
*/
public void produce() throws InterruptedException {
synchronized (lock) {
// 如果已經(jīng)生產(chǎn)了數(shù)據(jù),等待消費(fèi)者消費(fèi)
while (isProduced) {
lock.wait();
}
// 生產(chǎn)數(shù)據(jù)
System.out.println(Thread.currentThread().getName() + " produced data.");
isProduced = true;
// 通知消費(fèi)者可以消費(fèi)數(shù)據(jù)了
lock.notify();
}
}
/**
* 消費(fèi)者方法,等待生產(chǎn)者生產(chǎn)數(shù)據(jù)并進(jìn)行消費(fèi)
* @throws InterruptedException 當(dāng)線程被中斷時(shí)拋出異常
*/
public void consume() throws InterruptedException {
synchronized (lock) {
// 如果還沒(méi)有生產(chǎn)數(shù)據(jù),等待生產(chǎn)者生產(chǎn)
while (!isProduced) {
lock.wait();
}
// 消費(fèi)數(shù)據(jù)
System.out.println(Thread.currentThread().getName() + " consumed data.");
isProduced = false;
// 通知生產(chǎn)者可以繼續(xù)生產(chǎn)數(shù)據(jù)了
lock.notify();
}
}
/**
* 主程序入口,創(chuàng)建生產(chǎn)者和消費(fèi)者線程并運(yùn)行
* @param args 默認(rèn)參數(shù)
*/
public static void main(String[] args) {
WaitNotifyExample example = new WaitNotifyExample();
// 創(chuàng)建生產(chǎn)者線程
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
example.produce();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Producer");
// 創(chuàng)建消費(fèi)者線程
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
example.consume();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Consumer");
producer.start();
consumer.start();
}
}
8. 總結(jié)
Java 提供了多種用于線程同步的機(jī)制,包括 synchronized?、ReentrantLock?、ReentrantReadWriteLock?、Atomic? 類(lèi)、CyclicBarrier? 以及 Object? 的 wait()?/notify()?。每種方式都有其適用場(chǎng)景和優(yōu)缺點(diǎn)。對(duì)于簡(jiǎn)單的同步需求,synchronized? 是一種直接而有效的選擇;對(duì)于復(fù)雜的并發(fā)控制,Lock? 提供了更靈活的鎖機(jī)制;而 wait()? 和 notify()? 可以實(shí)現(xiàn)線程之間的協(xié)調(diào)工作。
到此這篇關(guān)于Java 中使用同步線程的多種實(shí)現(xiàn)方式的文章就介紹到這了,更多相關(guān)Java 同步線程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用Junit4.jar進(jìn)行單元測(cè)試的方法
今天通過(guò)本文給大家介紹Java使用Junit4.jar進(jìn)行單元測(cè)試的方法,本文通過(guò)圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-11-11
java8如何根據(jù)list對(duì)象中的屬性過(guò)濾篩選
這篇文章主要介紹了java8如何根據(jù)list對(duì)象中的屬性過(guò)濾篩選,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
JAVA MyBatis入門(mén)學(xué)習(xí)過(guò)程記錄
MyBatis是一個(gè)支持普通SQL查詢,存儲(chǔ)過(guò)程和高級(jí)映射的優(yōu)秀持久層框架。這篇文章主要介紹了mybatis框架入門(mén)學(xué)習(xí)教程,需要的朋友可以參考下,希望能幫助到你2021-06-06
idea微服務(wù)項(xiàng)目服務(wù)如何顯示在同一窗口
本文介紹了如何在微服務(wù)項(xiàng)目導(dǎo)入時(shí)將所有服務(wù)加入同一窗口中,解決啟動(dòng)項(xiàng)目服務(wù)時(shí)顯示不全的問(wèn)題,通過(guò)點(diǎn)擊左上角的View,選擇ToolWindows,然后選擇Services,使用快捷鍵Alt+8,選擇Spring Boot,就可以將所有服務(wù)加到同一窗口中2025-02-02
java?使用HanLP?安裝入門(mén)詳細(xì)教程
本文介紹Java使用HanLP的入門(mén)教程,涵蓋安裝、分詞、詞性標(biāo)注、關(guān)鍵詞提取、NER等核心功能,強(qiáng)調(diào)其功能完善、性能高效、支持自定義詞典的特點(diǎn),并提供配置方法和常見(jiàn)問(wèn)題解決方案,適合中文NLP開(kāi)發(fā)場(chǎng)景,感興趣的朋友一起跟隨小編看看吧2025-07-07
Java高性能本地緩存框架Caffeine的實(shí)現(xiàn)
本文主要介紹了Java高性能本地緩存框架Caffeine的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02

