Java併發程式設計中的鎖機制詳解
大家好,我是微賺淘客系統3.0的小編,是個冬天不穿秋褲,天冷也要風度的程式猿!
在Java併發程式設計中,鎖機制是保證執行緒安全的重要手段。鎖的作用是確保同一時刻只有一個執行緒能夠訪問被鎖保護的資源,從而避免資料不一致和併發衝突。本文將詳細介紹Java併發程式設計中的鎖機制,包括內建鎖、重入鎖、讀寫鎖等,並透過程式碼示例講解其使用方法和原理。
1. 內建鎖(synchronized)
Java的內建鎖是透過synchronized
關鍵字實現的,synchronized
可以用來修飾方法或者程式碼塊,確保同一時刻只有一個執行緒能夠執行被synchronized
保護的程式碼。
package cn.juwatech.lock;
public class SynchronizedDemo {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
SynchronizedDemo demo = new SynchronizedDemo();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
demo.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + demo.getCount());
}
}
在上述程式碼中,increment
方法被synchronized
修飾,保證了count
變數的自增操作是執行緒安全的。
2. 重入鎖(ReentrantLock)
ReentrantLock
是Java併發包中的可重入鎖,它提供了比synchronized
更靈活的鎖機制。例如,ReentrantLock
可以實現公平鎖、非阻塞地獲取鎖等功能。
package cn.juwatech.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
ReentrantLockDemo demo = new ReentrantLockDemo();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
demo.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final count: " + demo.getCount());
}
}
上述程式碼中,increment
方法使用ReentrantLock
進行加鎖和解鎖,確保count
變數的自增操作是執行緒安全的。
3. 讀寫鎖(ReadWriteLock)
ReadWriteLock
是另一種常用的鎖機制,它允許多個讀執行緒併發地訪問,但寫執行緒是獨佔的。這在讀多寫少的場景中可以顯著提高併發效能。
package cn.juwatech.lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {
private int count = 0;
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
public void increment() {
rwLock.writeLock().lock();
try {
count++;
} finally {
rwLock.writeLock().unlock();
}
}
public int getCount() {
rwLock.readLock().lock();
try {
return count;
} finally {
rwLock.readLock().unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ReadWriteLockDemo demo = new ReadWriteLockDemo();
Runnable writeTask = () -> {
for (int i = 0; i < 1000; i++) {
demo.increment();
}
};
Runnable readTask = () -> {
for (int i = 0; i < 1000; i++) {
System.out.println("Count: " + demo.getCount());
}
};
Thread t1 = new Thread(writeTask);
Thread t2 = new Thread(readTask);
Thread t3 = new Thread(readTask);
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
System.out.println("Final count: " + demo.getCount());
}
}
在上述程式碼中,increment
方法使用寫鎖進行加鎖,getCount
方法使用讀鎖進行加鎖,確保讀寫操作的執行緒安全。
4. 鎖的條件變數
ReentrantLock
還提供了條件變數(Condition),可以實現更復雜的執行緒同步控制。透過Condition
物件,可以讓執行緒在某個條件下等待,直到條件滿足後再繼續執行。
package cn.juwatech.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionDemo {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean ready = false;
public void waitForCondition() {
lock.lock();
try {
while (!ready) {
condition.await();
}
System.out.println("Condition met, proceeding...");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
public void signalCondition() {
lock.lock();
try {
ready = true;
condition.signalAll();
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ConditionDemo demo = new ConditionDemo();
Runnable waitingTask = demo::waitForCondition;
Runnable signalingTask = demo::signalCondition;
Thread t1 = new Thread(waitingTask);
Thread t2 = new Thread(signalingTask);
t1.start();
Thread.sleep(1000);
t2.start();
t1.join();
t2.join();
}
}
在上述程式碼中,waitForCondition
方法在條件不滿足時等待,直到signalCondition
方法將條件置為滿足並通知所有等待執行緒。
5. StampedLock
StampedLock
是Java 8引入的一種鎖機制,它提供了更高效的讀寫鎖,並且支援樂觀讀操作。StampedLock
的主要特點是它使用了戳記(stamp)來控制鎖的狀態。
package cn.juwatech.lock;
import java.util.concurrent.locks.StampedLock;
public class StampedLockDemo {
private int count = 0;
private final StampedLock stampedLock = new StampedLock();
public void increment() {
long stamp = stampedLock.writeLock();
try {
count++;
} finally {
stampedLock.unlockWrite(stamp);
}
}
public int getCount() {
long stamp = stampedLock.tryOptimisticRead();
int currentCount = count;
if (!stampedLock.validate(stamp)) {
stamp = stampedLock.readLock();
try {
currentCount = count;
} finally {
stampedLock.unlockRead(stamp);
}
}
return currentCount;
}
public static void main(String[] args) throws InterruptedException {
StampedLockDemo demo = new StampedLockDemo();
Runnable writeTask = () -> {
for (int i = 0; i < 1000; i++) {
demo.increment();
}
};
Runnable readTask = () -> {
for (int i = 0; i < 1000; i++) {
System.out.println("Count: " + demo.getCount());
}
};
Thread t1 = new Thread(writeTask);
Thread t2 = new Thread(readTask);
Thread t3 = new Thread(readTask);
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
System.out.println("Final count: " + demo.getCount());
}
}
在上述程式碼中,increment
方法使用寫鎖進行加鎖,getCount
方法嘗試使用樂觀讀鎖,如果失敗則降級為悲觀讀鎖,確保讀寫操作的執行緒安全。
總結
本文詳細介紹了Java併發程式設計中的鎖機制,包括內建鎖、重入鎖、讀寫鎖、條件變數和StampedLock
。透過這些示例程式碼,開發者可以更好地理解和使用Java的各種鎖機制,提高併發程式的效能和可靠性。
著作權歸聚娃科技微賺淘客系統開發者團隊,轉載請註明出處!