日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

对象及变量的并发访问一

發布時間:2025/6/17 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 对象及变量的并发访问一 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、多個線程操作一個對象實例 ?當兩個線程同時訪問一個沒有同步的方法,如果兩個線程同時操作業務對象中的實例變量,則有可能會出現“非線程安全問題”。 1 package concurrent; 2 /** 3 * 測試不同線程操作同一個實例變量線程安全問題 4 * @author foolishbird_lmy 5 * 6 */ 7 class ThePrivateNumber{ 8 private int num = 0; 9 10 public synchronized void addI(String username){ 11 try { 12 if (username.equals("a" )){ 13 num = 100; 14 System. out .println("a set over!"); 15 Thread. sleep(2000); 16 } else { 17 num = 200; 18 System. out .println("b set over!"); 19 } 20 System. out .println(Thread.currentThread().getName()+ " num is " +num ); 21 } catch (InterruptedException e){ 22 e.printStackTrace(); 23 } 24 } 25 } 26 27 class ThePrivateNumA extends Thread{ 28 private ThePrivateNumber tNumber; 29 public ThePrivateNumA(ThePrivateNumber tNumber){ 30 this .tNumber = tNumber; 31 } 32 public void run(){ 33 tNumber.addI( "a" ); 34 } 35 } 36 class ThePrivateNumB extends Thread{ 37 private ThePrivateNumber tNumber; 38 public ThePrivateNumB(ThePrivateNumber tNumber){ 39 this .tNumber = tNumber; 40 } 41 public void run(){ 42 tNumber.addI( "b" ); 43 } 44 } 45 public class ThePrivateNum { 46 public static void main(String[] args) { 47 ThePrivateNumber tNumber = new ThePrivateNumber(); 48 ThePrivateNumA tNumA = new ThePrivateNumA(tNumber); 49 tNumA.setName( "A" ); 50 tNumA.start(); 51 ThePrivateNumB tNumB = new ThePrivateNumB(tNumber); 52 tNumB.setName( "B" ); 53 tNumB.start(); 54 } 55 }

  

上面演示的就是兩個線程操作同一個對象實例,如果沒有加synchronized關鍵字執行同步,則會出現線程安全問題,也就是產生臟讀數據,即讀取到的數據是已經被修改過的數據; 分析:當線程A進入獲取到CPU執行權,匹配到“a”,則num=100,之后該線程被休眠2秒,此時B線程獲得CPU執行權,開始執行到else代碼,執行num=200,之后退出,A線程經過短暫休眠后自動蘇醒繼續執行,但是此時num已經被更改為了200,所以最后輸出num都是200,這就是線程非安全的;加了同步鎖之后,線程B必須等待線程A執行完之后才能進入,所以不會產生數據被修改問題。 二、一個對象實例中有同步方法與非同步方法 1 package concurrent; 2 3 class MySynchroized{ 4 public synchronized void methodA(){ 5 try { 6 System. out .println("the methodA is start:"+Thread. currentThread().getName()); 7 Thread. sleep(5000); 8 System. out .println("A end time "+System.currentTimeMillis ()); 9 } catch (InterruptedException e){ 10 e.printStackTrace(); 11 } 12 } 13 //synchronized,分別測試加同步鎖與不加執行順序 14 public void methodB(){ 15 try { 16 System. out .println("the methodB is start:"+Thread. currentThread().getName()); 17 System. out .println("B begin time "+System.currentTimeMillis ()); 18 Thread. sleep(5000); 19 } catch (InterruptedException e){ 20 e.printStackTrace(); 21 } 22 } 23 } 24 class TestA extends Thread{ 25 private MySynchroized ms; 26 public TestA(MySynchroized ms){ 27 this .ms = ms; 28 } 29 public void run(){ 30 ms.methodA(); //調用同步方法 31 } 32 } 33 class TestB extends Thread{ 34 private MySynchroized ms; 35 public TestB(MySynchroized ms){ 36 this .ms = ms; 37 } 38 public void run(){ 39 ms.methodB(); //調用非同步方法 40 } 41 } 42 public class TestSynchroized { 43 public static void main(String[] args) { 44 MySynchroized ms = new MySynchroized(); 45 TestA a = new TestA(ms); 46 a.setName( "A" ); 47 TestB b = new TestB(ms); 48 b.setName( "B" ); 49 a.start(); 50 b.start(); 51 } 52 }

  

分析:在共享的對象實例類中有兩個方法,我們分別設置為同步與非同步, (1)左邊是B方法非同步測試效果,我們可以看到,當執行A線程時,A拿到該對象的實例鎖,但是并沒有影響線程B執行非同步的方法,說明A、B線程幾乎是同時進行,B線程并沒有因為A拿到鎖而發生等待現象,屬于異步執行; (2)右邊是將B方法也執行同步,可以看到A、B線程同步執行即順序執行,當A先進入拿到對象鎖,B此時就會是同步等待狀態,只有當A執行休眠完成,釋放鎖之后B才有機會執行,屬于同步執行操作。 結論:對于執行相同對象的不同線程,執行對象類中的同步方法時,不管有多少個同步的方法,都是同一個對象鎖,必須等一個線程執行完畢釋放鎖之后另一個線程才能獲取執行;但是非同步方法可以任意時刻調用,不收鎖限制。 三、關于臟讀問題 1 package concurrent; 2 class DirtyRead { 3 private String name = "a" ; 4 private String id = "aa" ; 5 public synchronized void set(String name, String id) { 6 try { 7 this .name = name; 8 Thread. sleep(2000); 9 this .id = id; 10 System. out .println("set method " + Thread.currentThread().getName() 11 + " name:" + name + " id:" + id); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 } 16 public void get() { 17 System. out .println("get method " + Thread.currentThread().getName() 18 + " name:" + name + " id:" + id ); 19 } 20 } 21 class DirtyReadRun extends Thread { 22 private DirtyRead dr; 23 public DirtyReadRun(DirtyRead dr) { 24 this .dr = dr; 25 } 26 public void run() { 27 dr.set( "b" , "bb" ); 28 } 29 } 30 public class TestDirtyRead { 31 public static void main(String[] args) { 32 try { 33 DirtyRead dr = new DirtyRead(); 34 DirtyReadRun drr = new DirtyReadRun(dr); 35 drr.start(); 36 // Thread.sleep(1000); 37 Thread. sleep(3000); 38 dr.get(); 39 } catch (InterruptedException e) { 40 e.printStackTrace(); 41 } 42 } 43 }

  

分析: (1)左邊結果是在主線程中休眠1秒,可以發現讀取數據發生了錯誤,原因是我們將set方法設置為同步,所以線程在執行時拿到鎖后會安全執行,數據的設置沒有問題,但是當我們調用非同步方法get獲取值時,注意主線程只休眠了1秒,但是我們在set線程中休眠了2秒,所以此時線程并沒有來得及給id賦值操作,就直接輸出了aa而不是bb; (2)右邊是主線程休眠3秒的情況,即調用get方法的線程是在線程賦值set休眠2秒之后才調用,此時已經安全給數據賦值了,所以輸出結果正確; 當然我們也可以直接給get方法執行同步操作,這有另一個線程就必須等待第一個線程執行完set里面的全部操作釋放鎖之后才能執行,會發生等待。 四、鎖的可重入   關鍵字synchronized擁有可重入的功能,即當一個線程得到一個對象鎖之后,再次請求此對象鎖時是可以再次得到該對象的鎖的,自己可以再次獲取自己的內部鎖。 1 package concurrent; 2 /** 3 * 可重入鎖測試 4 * @author foolishbird_lmy 5 * 6 */ 7 class Synch{ 8 public synchronized void sA(){ 9 System. out .println("sA()" ); 10 sB(); 11 } 12 public synchronized void sB(){ 13 System. out .println("sB()" ); 14 sC(); 15 } 16 public synchronized void sC(){ 17 System. out .println("sC()" ); 18 } 19 } 20 class SynchARun extends Thread{ 21 private Synch sa; 22 public SynchARun(Synch sa){ 23 this .sa = sa; 24 } 25 public void run(){ 26 sa.sA(); 27 } 28 } 29 public class ReSynchronized { 30 public static void main(String[] args) { 31 SynchARun sa = new SynchARun( new Synch()); 32 sa.start(); 33 } 34 }

?  從輸出結果可以看出,線程只要獲取到了該對象鎖,其他的同步鎖也一樣能獲取。

?

五、靜態同步synchronized方法與synchronized(class)代碼塊

  ?用static修飾的同步方法中的同步鎖是給Class類上鎖,而非static方法是給對象上鎖;

?

1 package concurrent; 2 3 class StaticSyn { 4 public static synchronized void printA() { 5 try { 6 System. out .println(Thread.currentThread().getName() + " : " 7 + System.currentTimeMillis() + "進入printA()"); 8 Thread. sleep(3000); 9 System. out .println(Thread.currentThread().getName() + " : " 10 + System.currentTimeMillis() + "退出printA()"); 11 } catch (InterruptedException e) { 12 e.printStackTrace(); 13 } 14 } 15 public static synchronized void printB() { 16 try { 17 System. out .println(Thread.currentThread().getName() + " : " 18 + System.currentTimeMillis() + "進入printB()"); 19 Thread. sleep(3000); 20 System. out .println(Thread.currentThread().getName() + " : " 21 + System.currentTimeMillis() + "退出printB()"); 22 } catch (InterruptedException e) { 23 e.printStackTrace(); 24 } 25 } 26 public synchronized void printC() { 27 try { 28 System. out .println(Thread.currentThread().getName() + " : " 29 + System.currentTimeMillis() + "進入printC()"); 30 Thread. sleep(3000); 31 System. out .println(Thread.currentThread().getName() + " : " 32 + System.currentTimeMillis() + "退出printC()"); 33 } catch (InterruptedException e) { 34 e.printStackTrace(); 35 } 36 } 37 } 38 class StaticSynRunA extends Thread{ 39 private StaticSyn ss; 40 public StaticSynRunA(StaticSyn ss){ 41 this .ss = ss; 42 } 43 @SuppressWarnings( "static-access" ) 44 public void run(){ 45 ss. printA(); 46 } 47 } 48 class StaticSynRunB extends Thread{ 49 private StaticSyn ss; 50 public StaticSynRunB(StaticSyn ss){ 51 this .ss = ss; 52 } 53 public void run(){ 54 ss .printB (); 55 } 56 } 57 class StaticSynRunC extends Thread{ 58 private StaticSyn ss; 59 public StaticSynRunC(StaticSyn ss){ 60 this .ss = ss; 61 } 62 public void run(){ 63 ss.printC(); 64 } 65 } 66 public class TestStaticSyn { 67 public static void main(String[] args) { 68 StaticSyn ss = new StaticSyn(); 69 StaticSynRunA ssa = new StaticSynRunA(ss); 70 ssa.setName( "A" ); 71 ssa.start(); 72 StaticSynRunB ssb = new StaticSynRunB(ss); 73 ssb.setName( "B" ); 74 ssb.start(); 75 StaticSynRunC ssc = new StaticSynRunC(ss); 76 ssc.setName( "C" ); 77 // ssc.start(); 78 } 79 }

?

分析: (1)左邊結果是注釋掉C,即A、B線程都是調用靜態的同步方法,所以都是同步順序執行,他們的鎖都是Class鎖,是同一種鎖,所以B線程必須等待A線程釋放鎖; (2)右邊的結果是A、B、C線程同時運行,由于C線程調用的是非靜態的同步方法,非靜態的同步方法是對象鎖,與其他兩個線程的鎖不一樣,所以是異步的,但是A與B還是同步執行。

?

轉載于:https://www.cnblogs.com/lmy-foolishbird/p/5471853.html

總結

以上是生活随笔為你收集整理的对象及变量的并发访问一的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。