国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

synchronized同步引發的思考

2019-11-15 00:50:44
字體:
來源:轉載
供稿:網友
synchronized同步引發的思考

  最近公司某同事非常愛學,下班回家后也會抱書學習,看到多線程寫例子的時候遇到了非常奇怪的問題,故而將例子發給我看讓給解答,下面給出例子。

  1.第一例及運行結果

    下面是示例代碼

 1 package com.coderweb.sys.util; 2  3 public class TxtThread implements Runnable { 4  5     Integer num = 10000; 6     String str = new String(); 7  8     @Override 9     public void run() {10         synchronized (num) {11             while (true) {12                 if (num > 0) {13                     try {14                         // Thread.sleep(10);15                     } catch (Exception e) {16                         e.getMessage();17                     }18                     System.out.PRintln(Thread.currentThread().getName()19                             + " this is " + num--);20 21                     // str+="1";22                 } else {23                     break;24                 }25 26             }27         }28     }29 30     public static void main(String[] args) {31         TxtThread tt = new TxtThread();32         new Thread(tt).start();33         new Thread(tt).start();34         new Thread(tt).start();35         new Thread(tt).start();36     }37 }
View Code

    下面是運行截圖的一部分

Thread-0 this is 10000Thread-2 this is 9999Thread-0 this is 9998Thread-2 this is 9997Thread-3 this is 9995Thread-0 this is 9996Thread-3 this is 9993Thread-3 this is 9991Thread-3 this is 9990Thread-3 this is 9989Thread-3 this is 9988Thread-3 this is 9987Thread-3 this is 9986Thread-3 this is 9985

   問題一:Integer不是對象嗎?對象引用不變的呀?修改值后應該不變的呀?為啥起了四個線程后,四個線程都對一個對象里的值進行修改了呢?為啥synchronized語句塊沒有起到任何作用呢?

   帶著問題一,修改例子

   2.第二例及運行結果(唯一不同的地方是,synchronized(中的內容))

 1 package com.coderweb.sys.util; 2  3 public class TxtThread implements Runnable { 4  5     Integer num = 10000; 6     String str = new String(); 7  8     @Override 9     public void run() {10         synchronized (str) {11             while (true) {12                 if (num > 0) {13                     try {14                         // Thread.sleep(10);15                     } catch (Exception e) {16                         e.getMessage();17                     }18                     System.out.println(Thread.currentThread().getName()19                             + " this is " + num--);20 21                     // str+="1";22                 } else {23                     break;24                 }25 26             }27         }28     }29 30     public static void main(String[] args) {31         TxtThread tt = new TxtThread();32         new Thread(tt).start();33         new Thread(tt).start();34         new Thread(tt).start();35         new Thread(tt).start();36     }37 }
View Code

    運行結果部分

Thread-0 this is 10000Thread-0 this is 9999Thread-0 this is 9998Thread-0 this is 9997Thread-0 this is 9996Thread-0 this is 9995

.........

Thread-0 this is 5Thread-0 this is 4Thread-0 this is 3Thread-0 this is 2Thread-0 this is 1

通過問題2,可以得出總結,對于String字符串在初始化后,其引用地址沒有發生變化,后面也沒有進行修改,因此多個線程同時訪問的時候起到了互斥的作用,當四個線程啟動后,哪個線程先進入代碼塊進行了加鎖,誰將一直持有該鎖直到該線程結束,其余線程發現有線程持有該string的鎖,將處于等待狀態,因此結論便是,這四個線程,哪個線程先進入同步快,將一直打印該線程的數據。

由問題1跟2的不同運行結果發現,區別之處在于第一例子中的synchronized是num,并在后面進行了減法操作,而第二個例子中的synchronized是str,并且該str沒有發生變化,難道是因為num改變之后引用地址發生變化了?下面給出思考問題的驗證例子3跟4

3.第三例及運行結果

package com.coderweb.sys.util;public class TxtThread implements Runnable {    Integer num = 10000;    String str = new String();    Integer testI = 0;    @Override    public void run() {        synchronized (testI) {            while (true) {                if (num > 0) {                    try {                        // Thread.sleep(10);                    } catch (Exception e) {                        e.getMessage();                    }                    System.out.println(Thread.currentThread().getName()                            + " this is " + num--);                    // str+="1";                } else {                    break;                }            }        }    }    public static void main(String[] args) {        TxtThread tt = new TxtThread();        new Thread(tt).start();        new Thread(tt).start();        new Thread(tt).start();        new Thread(tt).start();    }}
View Code

    運行結果

Thread-0 this is 10000Thread-0 this is 9999Thread-0 this is 9998Thread-0 this is 9997Thread-0 this is 9996Thread-0 this is 9995Thread-0 this is 9994Thread-0 this is 9993

。。。。。。

Thread-0 this is 7Thread-0 this is 6Thread-0 this is 5Thread-0 this is 4Thread-0 this is 3Thread-0 this is 2Thread-0 this is 1

  該例子的不同之處在于,新加了一個成員變量testI,并且沒有對該值進行操作,發現結果居然成功,只有一個線程持有鎖,這也就驗證了Integer類型的確是引用類型,在

創建完成后的引用地址沒有發生變化。那么猜想string如果內容變了會怎樣呢?例子4進行驗證

  4.第四例及運行結果

 1 package com.coderweb.sys.util; 2  3 public class TxtThread implements Runnable { 4  5     Integer num = 10000; 6     String str = new String(); 7  8     @Override 9     public void run() {10         synchronized (str) {11             while (true) {12                 if (num > 0) {13                     try {14                         // Thread.sleep(10);15                     } catch (Exception e) {16                         e.getMessage();17                     }18                     System.out.println(Thread.currentThread().getName()19                             + " this is " + num--);20 21                      str+="1";22                 } else {23                     break;24                 }25 26             }27         }28     }29 30     public static void main(String[] args) {31         TxtThread tt = new TxtThread();32         new Thread(tt).start();33         new Thread(tt).start();34         new Thread(tt).start();35         new Thread(tt).start();36     }37 }
View Code

  運行部分結果

     .............................

Thread-3 this is 9774Thread-2 this is 9779Thread-3 this is 9773Thread-0 this is 9777Thread-3 this is 9771Thread-3 this is 9769Thread-3 this is 9768Thread-2 this is 9772Thread-3 this is 9767Thread-0 this is 9770Thread-3 this is 9765Thread-2 this is 9766Thread-3 this is 9763Thread-0 this is 9764Thread-3 this is 9761

..............................

該例子的不同之處在于,在循環最后不停的對str進行修改,所以導致了多個線程同時訪問,并沒有起到加鎖的作用。

但是我們的都知道,string類型變量是不可變的,也就是所說的immutable,就是說在對象創建之后,該string的引用類型變量是不變的,如果對該變量進行修改操作之后,會重新建立對象,并將新對象的地址賦給該引用,也就是說例子中的不停的修改str對象就相當于不停的創建新對象并賦給該引用。這個例子還好理解,畢竟我們對string還稍微有點了解,但是為什么Integer也會有這樣的效果呢,難道我們對Integer進行了修改之后起引用地址也發生了變化?下面查看了jdk關于Integer封裝類的源碼

5.JDK中關于Integer的部分源碼

public final class Integer extends Number implements Comparable<Integer> {         /**     * The value of the <code>Integer</code>.     *     * @serial     */    private final int value;/**     * Compares this object to the specified object.  The result is     * <code>true</code> if and only if the argument is not     * <code>null</code> and is an <code>Integer</code> object that     * contains the same <code>int</code> value as this object.     *     * @param   obj   the object to compare with.     * @return  <code>true</code> if the objects are the same;     *          <code>false</code> otherwise.     */    public boolean equals(Object obj) {    if (obj instanceof Integer) {        return value == ((Integer)obj).intValue();    }    return false;    } /**     * Returns a hash code for this <code>Integer</code>.     *     * @return  a hash code value for this object, equal to the      *          primitive <code>int</code> value represented by this      *          <code>Integer</code> object.      */    public int hashCode() {    return value;    }

  觀察上面的源碼我們便能明白道理了,在Integer封裝類中,利用了一個final的int類型,也就是說一旦對象創建,該值便不能改變了,但是為啥我們還能對其進行修改呢,所以必定是我們修改了之后,會創建新的地址,并賦給新的引用,我們先通過下面例子驗證一把是否引用地址發生了變化

  

 1 public static void main(String[] args) { 2 //        TxtThread tt = new TxtThread(); 3 //        new Thread(tt).start(); 4 //        new Thread(tt).start(); 5 //        new Thread(tt).start(); 6 //        new Thread(tt).start(); 7          8         Integer number = 5; 9         Integer number2 = number;10         number2--;11         System.out.println("number---"+number);12         System.out.println("number2---"+number2);13         System.out.println("number ==number2? "+(number==number2));14     }
View Code

  這個例子中,我們定義了第一個對象,這個時候第一個對象地址沒有發生變化,這時我們創建了新對象,并指向第一個對象,這時候兩個對象的引用地址是一樣的,緊接著我們對第二個對象進行了修改,當然其值是發生了變化,其實我們可以想一下,如果地址沒有發生變化的話,5是怎么等于4的呢?所以地址必然不一樣,最后的false也就驗證了這一點。當然咱通過Integer的源代碼發現,其equals方法也是通過判斷其中的值類判斷兩個Integer是否相等的。

    綜上所有事例得出結論:Integer這類對于基本數據類型的封裝類,當其值發生改變時,其引用地址也發生了變化。

  


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 晴隆县| 侯马市| 中阳县| 嵊州市| 兴海县| 吴江市| 娄烦县| 石门县| 腾冲县| 泽州县| 清水河县| 萝北县| 库车县| 夏津县| 平安县| 兴化市| 鄂托克旗| 右玉县| 蓝山县| 呼和浩特市| 金平| 盐边县| 吉木乃县| 呼玛县| 闵行区| 鞍山市| 海晏县| 油尖旺区| 遵义市| 历史| 铅山县| 合江县| 蒙自县| 昌宁县| 商丘市| 太仆寺旗| 岫岩| 泰和县| 东丰县| 贵州省| 资兴市|