一、原子性
原子性是指一個操作是不可中斷的整體,要麼全部執行成功,要麼全部執行失敗。在多線程環境下,原子性是保證數據正確的基礎。
Java提供了synchronized關鍵字和java.util.concurrent.atomic包下的原子類來實現原子操作。
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
在上面的代碼中,通過synchronized關鍵字使increment方法變成原子操作,從而保證了count的正確性。
除此之外,還可以使用AtomicInteger這個原子類來實現計數器:
public class Counter {
private AtomicInteger count = new AtomicInteger();
public void increment() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
二、可見性
可見性是指當一個線程修改了共享變數時,另一個線程能夠立即看到這個修改。在多線程環境下,可見性是保證數據一致性的基礎。
Java提供了volatile關鍵字來實現可見性,它能夠保證在讀取和修改變數時,都是直接從內存中讀取和寫入,而不是從緩存中讀取和寫入。
public class Counter {
private volatile int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
三、有序性
有序性是指程序執行的順序與代碼的先後順序一致,Java中的指令重排可能會導致代碼執行的順序不一致,從而產生一系列問題。
Java提供了synchronized和volatile兩種方式來保證有序性。
在下面的例子中,線程A和線程B執行的結果可能會不同:
public class OrderExample {
private int x = 0;
private boolean flag = false;
public void write() {
x = 1;
flag = true;
}
public void read() {
if (flag) {
int y = x + 1;
}
}
}
在上面的代碼中,如果線程A先執行write方法,然後線程B執行read方法,在沒有任何同步措施的情況下,y可能為0而不是2。
使用volatile關鍵字可以避免指令重排:
public class OrderExample {
private volatile int x = 0;
private volatile boolean flag = false;
public void write() {
x = 1;
flag = true;
}
public void read() {
if (flag) {
int y = x + 1;
}
}
}
結語
並發編程是一個複雜的問題,掌握並發三大特性對於正確使用多線程至關重要。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/231918.html
微信掃一掃
支付寶掃一掃