讀后感
- 介紹了volatile實現可見性的基本原理
- 介紹了volatile不能實現原子性的示例,volatile復合操作不能實現原子性,讀取值后在自增前改值可能被其它線程讀取並修改,自增后刷新值可能會覆蓋其它線程修改后的值
- 介紹了實現原子性的三種方法及示例
- synchronized 修飾對象
- ReentrantLock 使用lock()、unlock()加鎖解鎖,比synchronized功能更多,JDK6后性能和synchronized差不多
- AtomicInteger 使用樂觀鎖
volatile關鍵字:
- 能夠保證volatile變量的可見性
- 不能保證volatile變量復合操作的原子性
volatile如何實現內存可見性:
深入來說:通過加入內存屏障和禁止重排序優化來實現的。
- 對volatile變量執行寫操作時,會在寫操作后加入一條store屏障指令
- 對volatile變量執行讀操作時,會在讀操作前加入一條load屏障指令
通俗地講:volatile變量在每次被線程訪問時,都強迫從主內存中重讀該變量的值,而當該變量發生變化時,又會強迫線程將最新的值刷新到主內存。這樣任何時刻,不同的線程總能看到該變量的最新值。
線程寫volatile變量的過程:
- 改變線程工作內存中volatile變量副本的值
- 將改變后的副本的值從工作內存刷新到主內存
線程讀volatile變量的過程:
- 從主內存中讀取volatile變量的最新值到線程的工作內存中
- 從工作內存中讀取volatile變量的副本
volatile不能保證volatile變量復合操作的原子性:
- private int number = 0;
- number++; //不是原子操作
它分為三步:
讀取number的值
將number的值加1
寫入最新的number的值
保證number自增操作的原子性:
- 使用synchronized關鍵字
- 使用ReentrantLock
- 使用AtomicInteger
使用synchronized關鍵字
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- /**
- * @author InJavaWeTrust
- */
- public class TestSyn implements Runnable {
- private int number = 0;
- public int getNumber() {
- return this.number;
- }
- public void run() {
- increase();
- }
- public void increase() {
- synchronized (this) {
- this.number++;
- }
- }
- public static void main(String[] args) {
- ExecutorService exec = Executors.newFixedThreadPool(1000);
- TestSyn syn = new TestSyn();
- for (int i = 0; i < 1000; i++) {
- exec.submit(syn);
- }
- System.out.println("number : " + syn.getNumber());
- exec.shutdown();
- }
- }
使用ReentrantLock
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- * @author InJavaWeTrust
- */
- public class TestRee implements Runnable {
- private Lock lock = new ReentrantLock();
- private int number = 0;
- public int getNumber() {
- return this.number;
- }
- public void run() {
- increase();
- }
- public void increase() {
- lock.lock();
- try {
- this.number++;
- } finally {
- lock.unlock();
- }
- }
- public static void main(String[] args) {
- TestRee ree = new TestRee();
- ExecutorService exec = Executors.newFixedThreadPool(1000);
- for (int i = 0; i < 1000; i++) {
- exec.submit(ree);
- }
- System.out.println("number : " + ree.getNumber());
- exec.shutdown();
- }
- }
使用AtomicInteger
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.atomic.AtomicInteger;
- /**
- * @author InJavaWeTrust
- */
- public class TestAtomic implements Runnable {
- private static AtomicInteger number = new AtomicInteger(0);
- public void run() {
- increase();
- }
- public void increase() {
- number.getAndAdd(1);
- }
- public static void main(String[] args) {
- TestAtomic ato = new TestAtomic();
- ExecutorService exec = Executors.newFixedThreadPool(1000);
- for (int i = 0; i < 1000; i++) {
- exec.submit(ato);
- }
- System.out.println("number : " + number.get());
- exec.shutdown();
- }
- }




