一、原子性
原子性是指一個操作是不可中斷的整體,要麼全部執行成功,要麼全部執行失敗。在多線程環境下,原子性是保證數據正確的基礎。
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