當有多個線程設置對應的值的時候,讀取的值是不是那個線程設置的值???
若是咱們單獨對這個值上鎖的話,狀況會怎麼樣呢?
volatile Integer a = 0; /** * 當有多個線程設置對應的值的時候,讀取的值是不是那個線程設置的值??? * 事實證實,單獨上鎖,並不能保證數據的惟一性,由於在部分線程在進行設置值的時候,咱們並無設置讀鎖 * 也就是說,這些線程讀取的是以前的值,而不是線程阻塞設置的值 * 那麼這種狀況要怎麼才能保證讀寫一致呢??讀寫鎖。。。。 */ @Test public void test1() { //設置柵欄,保證同時啓動 CyclicBarrier cyclicBarrier = new CyclicBarrier(5); for (int i = 1; i < 6; ++i) { //每一個線程獲取並設置值 final int tmp = i; new Thread(new Runnable() { @Override public void run() { // System.out.println(Thread.currentThread().getName() + "準備:" + System.currentTimeMillis()); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } // System.out.println(Thread.currentThread().getName() + "開始:" + System.currentTimeMillis()); while (true) { synchronized (a) { // if (tmp == 5) { // try { // System.out.println(Thread.currentThread().getName() + "等待設置值:" + System.currentTimeMillis()); // Thread.sleep(4000); // } catch (InterruptedException e) { // e.printStackTrace(); // } // } a = tmp; System.out.println(Thread.currentThread().getName() + "設置a值:" + a + "---" + System.currentTimeMillis()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } // try { // Thread.sleep(2000); // } catch (InterruptedException e) { // e.printStackTrace(); // } System.out.println(Thread.currentThread().getName() + "-read a =:" + a); } } }).start(); } while (true) { int j = 1; } }
結果顯示:數據庫
咱們發現讀取的a值雜亂無章,並不能保證是這個線程設置以後的值,爲何爲這樣呢???網絡
由於咱們只對a進行上鎖的話,那麼在對a進行設置值的時候,其餘線程能夠繼續讀取a的值,當a的值設置完畢以後,其餘線程讀取的值,咱們也不知道是讀取那個線程設置的值ide
若是咱們把a設置爲數據庫的值的話,咱們會發現,不通的人請求拿到的結果竟然不是同樣的spa
很簡單舉個例子:線程
A系統請求,須要獲取某個地址信息的時候,B系統正在修改地址信息,那麼在B修改完成以後,這個值仍是能夠讀取的,只是不能被C系統修改而已code
可是若是出現網絡波動,或者業務邏輯比較複雜,那麼就會致使B尚未修改完畢,A就把以前的舊數據讀取過去了,這樣就致使A系統用了一個錯的地址信息,blog
結果就是地址錯了,業務也就作錯地方了,那麼緊接着是否是就應該是投訴了!!!get
那麼這種狀況要怎麼才能保證讀寫一致呢??
讀寫鎖,在讀的時候也要設置鎖,保證B系統在修改數據的時候,其餘系統沒法讀取
/** * 這樣就徹底一致了。。。。 * 可是這個鎖會致使效率極低,具體情境使用,看來仍是要分狀況啊 */ @Test public void test2() { final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); //設置柵欄,保證同時啓動 CyclicBarrier cyclicBarrier = new CyclicBarrier(5); for (int i = 1; i < 6; ++i) { //每一個線程獲取並設置值 final int tmp = i; new Thread(new Runnable() { @Override public void run() { try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } while (true) { //這裏對變量a上寫鎖 reentrantReadWriteLock.writeLock().lock(); reentrantReadWriteLock.readLock().lock(); a = tmp; System.out.println(Thread.currentThread().getName() + "設置a值:" + a + "---" + System.currentTimeMillis()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //讀數據的時候,不容許讀數據 reentrantReadWriteLock.readLock().unlock(); reentrantReadWriteLock.writeLock().unlock(); //這裏上讀鎖 System.out.println(Thread.currentThread().getName() + "-read a =:" + a); } } }).start(); } while (true) { int j = 1; } }
效果:it
可是想必你們也發現問題了,那就是效率極低io
可是若是數據是比較珍貴,核心的數據,這點效率的丟失是否值得就是須要權衡的東西了