Java 中使用同步線程的多種實現(xiàn)方式
1. 前序
在多線程編程中,線程同步是確保數(shù)據(jù)一致性和防止競態(tài)條件的關(guān)鍵。Java 提供了多種用于線程同步的機(jī)制,以解決不同場景下的線程競爭問題。無論是最基本的 synchronized? 關(guān)鍵字,還是更靈活的 ReentrantLock?、ReentrantReadWriteLock?,它們都為開發(fā)者提供了不同級別的鎖和控制。
本文將逐一介紹 Java 中常見的同步機(jī)制,涵蓋了 synchronized?、ReentrantLock?、Atomic? 類等,同時給出每種機(jī)制的示例代碼和適用場景,幫助你更好地理解并應(yīng)用這些同步機(jī)制。
2.synchronized?
2.1synchronized? 關(guān)鍵字
- 描述:Java 中最基礎(chǔ)的同步機(jī)制就是
synchronized? 關(guān)鍵字,它可以用于方法或代碼塊,確保同一時刻只有一個線程可以訪問共享資源。 - 示例代碼:
/**
* 示例類,演示如何使用 synchronized 方法進(jìn)行線程同步
*/
public class SynchronizedMethodExample {
/** 共享計數(shù)器 */
private int counter = 0;
/**
* 同步遞增計數(shù)器的方法,確保同一時刻只有一個線程可以執(zhí)行
*/
public synchronized void increment() {
// 遞增計數(shù)器
counter++;
// 輸出當(dāng)前線程和計數(shù)器的值
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
}
/**
* 主程序入口,創(chuàng)建多個線程并運(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)建兩個線程
Thread t1 = new Thread(task, "Thread 1");
Thread t2 = new Thread(task, "Thread 2");
// 啟動線程
t1.start();
t2.start();
}
}
2.2 使用synchronized? 代碼塊
- 描述:相比于
synchronized? 方法,synchronized? 代碼塊允許更細(xì)粒度地控制同步范圍??梢灾付ㄌ囟ǖ拇a塊進(jìn)行同步,而不是整個方法,這樣可以減少鎖的競爭,提高效率。 - 示例代碼:
/**
* 示例類,演示如何使用 synchronized 代碼塊進(jìn)行線程同步
*/
public class SynchronizedBlockExample {
/** 共享計數(shù)器 */
private int counter = 0;
/** 自定義鎖對象 */
private final Object lock = new Object();
/**
* 同步遞增計數(shù)器的方法,只鎖定代碼塊
*/
public void increment() {
// 使用 synchronized 代碼塊確保鎖定的粒度更小
synchronized (lock) {
counter++;
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
}
}
/**
* 主程序入口,創(chuàng)建多個線程并運(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? 接口的一個常用實現(xiàn),它提供了更靈活的鎖定機(jī)制,允許手動加鎖和解鎖。 - 示例代碼:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 示例類,演示如何使用 ReentrantLock 進(jìn)行線程同步
*/
public class LockExample {
/** 共享計數(shù)器 */
private int counter = 0;
/** ReentrantLock 實例 */
private final Lock lock = new ReentrantLock();
/**
* 同步遞增計數(shù)器的方法,手動加鎖和解鎖
*/
public void increment() {
// 獲取鎖
lock.lock();
try {
// 遞增計數(shù)器
counter++;
// 輸出當(dāng)前線程和計數(shù)器的值
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
} finally {
// 確保鎖在最后被釋放
lock.unlock();
}
}
/**
* 主程序入口,創(chuàng)建多個線程并運(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? 提供了讀寫鎖機(jī)制,可以讓多個線程并發(fā)讀取,但在寫入時只有一個線程可以操作。這樣可以提高在讀多寫少場景下的性能。 - 示例代碼:
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 示例類,演示如何使用 ReentrantReadWriteLock 進(jìn)行線程同步
*/
public class ReadWriteLockExample {
/** 共享計數(shù)器 */
private int counter = 0;
/** ReentrantReadWriteLock 實例 */
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
/**
* 獲取寫鎖并遞增計數(shù)器
*/
public void increment() {
// 獲取寫鎖
lock.writeLock().lock();
try {
// 遞增計數(shù)器
counter++;
System.out.println(Thread.currentThread().getName() + " - Write Counter: " + counter);
} finally {
// 釋放寫鎖
lock.writeLock().unlock();
}
}
/**
* 獲取讀鎖并讀取計數(shù)器
* @return 計數(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)建多個線程并運(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? 類
- 描述:
Atomic? 類位于java.util.concurrent.atomic? 包內(nèi),提供了常見的原子操作類(如AtomicInteger?),用于在無鎖的情況下對單一變量進(jìn)行線程安全的操作。 - 示例代碼:
import java.util.concurrent.atomic.AtomicInteger;
/**
* 示例類,演示如何使用 AtomicInteger 進(jìn)行線程同步
*/
public class AtomicExample {
/** 線程安全的 AtomicInteger */
private AtomicInteger counter = new AtomicInteger(0);
/**
* 原子性遞增計數(shù)器的方法
*/
public void increment() {
// 原子遞增
int newValue = counter.incrementAndGet();
System.out.println(Thread.currentThread().getName() + " - Counter: " + newValue);
}
/**
* 主程序入口,創(chuàng)建多個線程并運(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á)某個共同的屏障點時,才能繼續(xù)執(zhí)行。它支持重用,即可以被多次使用。 - 示例代碼:
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 示例類,演示如何使用 CyclicBarrier 實現(xiàn)線程同步
*/
public class CyclicBarrierExample {
/** CyclicBarrier 實例,等待 3 個線程 */
private final CyclicBarrier barrier = new CyclicBarrier(3, () -> {
// 所有線程到達(dá)屏障后執(zhí)行的操作
System.out.println("All threads have reached the barrier. Barrier action executed.");
});
/**
* 線程任務(wù),等待屏障點并繼續(xù)執(zhí)行
*/
public void performTask() {
System.out.println(Thread.currentThread().getName() + " is waiting at the barrier");
try {
// 等待其他線程到達(dá)屏障點
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " has crossed the barrier");
}
/**
* 主程序入口,創(chuàng)建多個線程并運(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? 類的wait()?、notify()? 和notifyAll()? 方法允許線程在某個條件下進(jìn)行等待和喚醒。與synchronized? 搭配使用,可以實現(xiàn)類似于信號量的功能。 - 示例代碼:
/**
* 示例類,演示如何使用 wait() 和 notify() 進(jìn)行線程同步
*/
public class WaitNotifyExample {
/** 自定義鎖對象 */
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)線程被中斷時拋出異常
*/
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)線程被中斷時拋出異常
*/
public void consume() throws InterruptedException {
synchronized (lock) {
// 如果還沒有生產(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? 類、CyclicBarrier? 以及 Object? 的 wait()?/notify()?。每種方式都有其適用場景和優(yōu)缺點。對于簡單的同步需求,synchronized? 是一種直接而有效的選擇;對于復(fù)雜的并發(fā)控制,Lock? 提供了更靈活的鎖機(jī)制;而 wait()? 和 notify()? 可以實現(xiàn)線程之間的協(xié)調(diào)工作。
到此這篇關(guān)于Java 中使用同步線程的多種實現(xiàn)方式的文章就介紹到這了,更多相關(guān)Java 同步線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用Junit4.jar進(jìn)行單元測試的方法
今天通過本文給大家介紹Java使用Junit4.jar進(jìn)行單元測試的方法,本文通過圖文實例相結(jié)合給大家介紹的非常詳細(xì),需要的朋友參考下吧2021-11-11
Java高性能本地緩存框架Caffeine的實現(xiàn)
本文主要介紹了Java高性能本地緩存框架Caffeine的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02

