一、volatile關鍵字
volatile關鍵字用於保證變量在多線程之間的可見性。通常情況下,線程之間是互相不可見的,也就是說一個線程對變量的修改,其他線程不會立即感知到。使用volatile聲明的變量可以保證當一個線程修改了該變量的值之後,其他線程能夠立即感知到這個變化。
public class VolatileTest {
private volatile int count = 0;
public void increment() {
count++;
}
public static void main(String[] args) throws InterruptedException {
final VolatileTest test = new VolatileTest();
for (int i = 0; i {
for (int j = 0; j < 1000; j++) {
test.increment();
}
}).start();
}
Thread.sleep(3000);
System.out.println(test.count);
}
}
上述代碼可以看出,由於count變量被volatile修飾,所以多個線程對該變量的修改是可見的,最終輸出的count變量的值是5000,而不是一個小於5000的數值。
二、synchronized關鍵字
synchronized關鍵字是Java中最基本的同步關鍵字,它用於保證多個線程之間的互斥訪問,允許在同一時刻只有一個線程訪問共享資源。
public class SynchronizedTest {
private int count = 0;
public synchronized void increment() {
count++;
}
public static void main(String[] args) throws InterruptedException {
final SynchronizedTest test = new SynchronizedTest();
for (int i = 0; i {
for (int j = 0; j < 1000; j++) {
test.increment();
}
}).start();
}
Thread.sleep(3000);
System.out.println(test.count);
}
}
上述代碼中,count變量被synchronized關鍵字修飾的increment方法訪問。由於synchronized保證了同一時刻只有一個線程可以進入該方法,所以最終輸出的count變量的值是5000。
三、ReentrantLock類
ReentrantLock類是Java中可重入鎖的一種實現方式,也可以實現多個線程之間的互斥訪問。與synchronized關鍵字不同的是,ReentrantLock類可以更加精細地控制鎖的獲取和釋放,同時還支持公平鎖和非公平鎖。
public class ReentrantLockTest {
private ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
final ReentrantLockTest test = new ReentrantLockTest();
for (int i = 0; i {
for (int j = 0; j < 1000; j++) {
test.increment();
}
}).start();
}
Thread.sleep(3000);
System.out.println(test.count);
}
}
上述代碼中,ReentrantLock類實現了多個線程之間的互斥訪問。在increment方法中,首先需要調用lock方法獲取鎖,保證同一時刻只有一個線程可以修改count變量的值,最後需要調用unlock方法釋放鎖。最終輸出的count變量的值是5000。
四、Condition接口
Condition接口是在Java 5中引入的,它提供了類似於Object的wait和notify方法的功能,但可以選擇性地地通知某些線程。與使用synchronized關鍵字和Object的wait方法不同,使用Condition對象可以在等待信號時釋放鎖。
public class ConditionTest {
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
condition.signalAll();
} finally {
lock.unlock();
}
}
public void waitForCount() throws InterruptedException {
lock.lock();
try {
while (count {
try {
test.waitForCount();
System.out.println("count has reached 5000");
} catch (InterruptedException ex) {
// ...
}
}).start();
for (int i = 0; i {
for (int j = 0; j < 1000; j++) {
test.increment();
}
}).start();
}
Thread.sleep(3000);
}
}
上述代碼中,ConditionTest類中的waitForCount方法會線程等待,直到count變量的值達到5000。在increment方法中,除了對count變量進行修改之外,還會調用signalAll方法通知所有等待線程。最終輸出的是「count has reached 5000」。
五、ReadWriteLock類
除了ReentrantLock之外,Java並發包中還提供了ReadWriteLock類,它可以使得多個線程同時讀取共享變量,但是在有線程寫入時,所有讀線程會被阻塞。
public class ReadWriteLockTest {
private int count = 0;
private ReadWriteLock lock = new ReentrantReadWriteLock();
public void increment() {
lock.writeLock().lock();
try {
count++;
} finally {
lock.writeLock().unlock();
}
}
public void printCount() {
lock.readLock().lock();
try {
System.out.println(count);
} finally {
lock.readLock().unlock();
}
}
public static void main(String[] args) throws InterruptedException {
final ReadWriteLockTest test = new ReadWriteLockTest();
for (int i = 0; i {
for (int j = 0; j < 1000; j++) {
test.increment();
}
}).start();
}
for (int i = 0; i {
for (int j = 0; j < 1000; j++) {
test.printCount();
}
}).start();
}
Thread.sleep(3000);
}
}
上述代碼中,increment方法使用寫鎖進行同步,而printCount方法使用讀鎖進行同步。由於讀鎖是共享鎖,多個線程可以同時獲得對共享變量的訪問權。最終輸出的count變量的值會大於等於5000。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/227820.html
微信掃一掃
支付寶掃一掃