《Java多線程 - 不要同步Boolean常量》測試代碼__java

來源:互聯網
上載者:User

《Java多線程 - 不要同步Boolean常量》

提出兩個觀點:

1.Boolean對象賦值為true和false,會改變指向的對象.

測試代碼:

private volatile Boolean isTrue = Boolean.FALSE; //此處用false也一樣 public void aMethod() {for (int i = 0; i < 10; i++) {Thread t = new Thread() {public void run() {synchronized (isTrue) {isTrue = !isTrue;System.out.println(Thread.currentThread().getName() + " - isTrue=" + isTrue);try {Double ran = 1000 * Math.random();Thread.sleep(ran.intValue());} catch (InterruptedException e) {}if (!isTrue)System.out.println(Thread.currentThread().getName() + " - Oh, No!");isTrue = !isTrue;System.out.println(Thread.currentThread().getName() + " exit");}}};t.start();}}

其中一次的運行結果:

Thread-0 - isTrue=trueThread-1 - isTrue=falseThread-0 - Oh, No!Thread-0 exitThread-9 - isTrue=falseThread-1 - Oh, No!Thread-1 exitThread-9 exitThread-8 - isTrue=trueThread-8 exitThread-7 - isTrue=trueThread-7 exitThread-6 - isTrue=trueThread-6 exitThread-5 - isTrue=trueThread-5 exitThread-4 - isTrue=trueThread-4 exitThread-3 - isTrue=trueThread-3 exitThread-2 - isTrue=trueThread-2 exit

按照一般的邏輯,isTrue作為共用對象被10個線程共用,每個線程的run方法代碼都被isTrue加鎖,應該是安全執行緒的,不應該輸出Oh, No!;但是輸出結果卻剛好相反;

分析原因:isTrue初始化被賦值為Boolean.false這個常量,進入run時,synchronized鎖的是Boolean.false這個對象,後取非,isTrue指向發生改變,指向Boolean.true這個常量,後麵線程進入run後synchronized鎖的Boolean.true這個對象,因此不會發生線程互斥,輸出Oh, No!,達不到安全執行緒目的。

2.以為同步的是不同對象,實際是一個對象。

import java.util.Random;public class BooleanTest {private volatile Boolean aBoolean = false;//Boolean.FALSE;  private volatile Boolean anotherBoolean = false;private long t1 = System.currentTimeMillis();public void aMethod2() {final Random random = new Random();for (int i = 0; i < 10; i++) {Thread t = new Thread() {public void run() {int val = random.nextInt();if (val % 2 == 0) {synchronized (aBoolean) {System.out.println(Thread.currentThread().getName() + " aBoolean_costMills:"+(System.currentTimeMillis() -t1));t1 = System.currentTimeMillis();try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}} else {synchronized (anotherBoolean) {System.out.println(Thread.currentThread().getName() + " anotherBoolean_costMills:"+(System.currentTimeMillis() -t1));t1 = System.currentTimeMillis();try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}}}}};t.start();}}public static void main(String... args) {BooleanTest bt = new BooleanTest();bt.aMethod2();}}
可能的輸出:

Thread-0 anotherBoolean_costMills:0Thread-9 aBoolean_costMills:204Thread-8 aBoolean_costMills:110Thread-7 aBoolean_costMills:109Thread-6 anotherBoolean_costMills:110Thread-5 anotherBoolean_costMills:204Thread-4 aBoolean_costMills:219Thread-1 aBoolean_costMills:110Thread-3 aBoolean_costMills:109Thread-2 aBoolean_costMills:110

分析原因:明明程式加了兩個鎖aBoolean,anotherBoolean,執行這兩個鎖裡面的代碼應該是互不干擾,但是列印卻顯示:如果先前執行的是aBoolean,後面執行的是anotherBoolean,需要等待110ms(正常應該是不等待);如果先前anotherBoolean,後面aBoolean,等待了204ms(正常應該是不等待);這說明這兩者執行發生了互斥;原因是aBoolean和anotherBoolean指向了同一對象Boolean.false;其實Boolean.FALSE和false指向的是同一個對象,因此aBoolean賦值Boolean.false還是false,效果一樣。


綜上:盡量不用使用Boolean對象作為被同步對象,不然可能會出現意想不到的問題,或者對以後的代碼修改造成陷阱。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.