多線程--畢向東java基礎教程視頻學習筆記


目錄

1.多線程運行的安全問題

2.多線程同步代碼塊

3.同步方法的鎖是this

4.靜態同步方法的鎖是Class對象

5.單例設計模式(面試中的考點)

6.死鎖(一個發生死鎖的例子)

 

多線程運行的安全問題

例子:售票系統

 1 class Ticket implements Runnable  2 {  3     //定義靜態變量ticket
 4     private static int ticket=100;  5     public void run()  6  {  7         while(true)  8  {  9             //判斷票編號是否大於0
10             if(ticket>0) 11  { 12                 try
13  { 14                     Thread.sleep(10); 15  } 16                 catch (InterruptedException ie) 17  { 18                     System.err.println("Error:"+ie); 19  } 20                 System.out.println(Thread.currentThread().getName()+"--sale:"+ticket--); 21  } 22  } 23  } 24 
25 } 26 public class ThreadDemo 27 { 28     
29     public static void main(String[] args) 30  { 31         //創建一個實現了Runnable接口的Ticket對象
32         Ticket t=new Ticket(); 33         //創建4個線程
34         Thread t1=new Thread(t); 35         Thread t2=new Thread(t); 36         Thread t3=new Thread(t); 37         Thread t4=new Thread(t); 38         //分別啟動4個線程
39  t1.start(); 40  t2.start(); 41  t3.start(); 42  t4.start(); 43 
44  } 45 }

運行:

最后,打印出了了“0,-1,-2”的錯票情況(票的編號從1-100).多線程出現安全問題。

 

問題的原因:

當多條語句在操作用一個線程共享數據時,一個線程對多條語句只執行了一部分,還沒執行完,

另一個數據參與進來執行,造成共享數據的錯誤。

解決方法:

對多條操作共享數據的語句,只能讓一個線程都執行完,在執行過程中不允許其他線程參與進來。

java對於多線程的同步提供了專業的解決方法,就是同步代碼塊。

 

多線程同步代碼塊

synchronized(對象)

{需要被同步的代碼塊}

對象如同鎖,持有鎖的線程可以在同步代碼塊中執行,

沒有持有鎖的線程即使獲得CPU的執行權也進不去,因為沒有獲取鎖。

 

例子:火車上的衛生間。

同步的前提:

1.必須要有兩個或者兩個以上的線程。

2.必須是多個線程使用同一把鎖。

 

好處:解決了多線程的安全問題。

弊端:需要判斷鎖,較為消耗資源。

 一般不可以把run()方法全放在同步代碼塊中,否則就是單線程了。

 

同步方法:

銀行
有兩個儲戶,分別存300元,每次存100元,存3次
目的:該線程是否有安全問題,如果有,如何解決?

如何找問題:
1.明確哪些代碼是多線程運行代碼
2.明確共享數據
3.明確多線程運行代碼中哪些代碼操作共享數據的。

 1 class Bank  2 {  3     //定義sum,代表銀行的總金額
 4     private int sum;  5     Object obj=new Object();  6     public void add(int n)  7  {  8         
 9         //sum為共享數據,對sum有兩句操作, 10         //防止出現不安全問題,使用同步代碼塊
11         synchronized(obj) 12  { 13             sum=sum+n; 14             try
15  { 16                 Thread.sleep(10); 17  } 18             catch (InterruptedException ie) 19  { 20                 System.err.println("Error:"+ie); 21  } 22             System.out.println("sum="+sum); 23  } 24  } 25 } 26 class Cus implements Runnable 27 { 28     private Bank b=new Bank(); 29     //存三次
30     public void run() 31  { 32         for(int i=0;i<3;i++) 33             b.add(100); 34  } 35 } 36 public class BankDemo 37 { 38     public static void main(String[] args) 39  { 40         Cus cus=new Cus(); 41         //創建兩個線程,代表2個儲戶的存錢過程
42         Thread t1=new Thread(cus); 43         Thread t2=new Thread(cus); 44  t1.start(); 45  t2.start(); 46  } 47 }

注:同步的兩種表現形式:a.同步代碼塊   b.同步函數

 

同步方法的鎖是this

同步方法用的是哪一個鎖呢?

方法需要被對象調用,那么方法都有一個所屬對象的引用,就是this。

所以同步方法的鎖就是this。

 

靜態同步方法的鎖是Class對象

當同步方法被靜態修飾后,使用的鎖就不是this了,因為靜態方法中不可以使用this。

靜態方法進內存時,內存沒有本類對象,但一定有該類對應的字節碼文件對象。

類名.class。該對象的類型是Class。

靜態同步方法,使用的鎖是該方法所在的類的字節碼文件對象。類名.class

 

單例設計模式

1.餓漢式

1 class Single 2 { 3     private static final Single s=new Single(); 4     private Single(){} 5     public static Single getInstance() 6  { 7         return s; 8  } 9 }

2.懶漢式:

 1 /*
 2 面試時的考點:  3 
 4 懶漢式的特點:實例的延遲加載  5 會出現的問題:多線程訪問時會出現安全問題  6 解決方法:用同步方法或者同步代碼塊都行,  7 但是有些低效,可以通過雙重判斷,減少判斷鎖的次數,稍微提高效率。  8 加同步時候:使用的鎖是該類的字節碼對象  9 
10 */
11 class Single 12 { 13     private static  Single s=null; 14     private Single(){} 15     public static Single getInstance() 16  { 17         //通過雙重判斷,減少判斷鎖的次數,稍微提高效率。
18         if (s==null) 19  { 20             synchronized (Single.class) 21  { 22                 if(s==null) 23                     s=new Single(); 24  } 25  } 26         return s; 27  } 28 }

 

死鎖:同步中嵌套同步

死鎖的例子

 1 class Test implements Runnable  2 {  3     private boolean flag;  4     Test(boolean _flag)  5  {  6         flag=_flag;  7  }  8     public void run()  9  { 10         if(flag) 11  { 12             synchronized(MyLock.locka) 13  { 14                 System.out.println("if locka"); 15                 synchronized(MyLock.lockb) 16  { 17                     System.out.println("if lockb"); 18 
19  } 20 
21  } 22 
23  } 24         else
25  { 26             synchronized(MyLock.lockb) 27  { 28                 System.out.println("else lockb"); 29                 synchronized(MyLock.locka) 30  { 31                     System.out.println("else locka"); 32 
33  } 34 
35  } 36 
37  } 38 
39  } 40 } 41 class MyLock 42 { 43     static Object locka=new Object(); 44     static Object lockb=new Object(); 45 } 46 public class DeadLockTest 47 { 48     public static void main(String[] args) 49  { 50         Thread t1=new Thread(new Test(true)); 51         Thread t2=new Thread(new Test(false)); 52  t1.start(); 53  t2.start(); 54 
55  } 56     
57 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM