Java多執行緒6 中同步函式的鎖和同步程式碼塊的鎖的區別
阿新 • • 發佈:2019-02-02
同步程式碼塊的出現是解決了多執行緒的安全問題,但是它增加了程式碼的縮排層級,同時降低了效率(每次無論是不是對的鎖,每個路徑都要去判斷)
針對同步出現的這兩個問題,首先討論第一個。因此引出一個新的知識點————————
同步函式
關於同步函式的使用(一買車票的程式碼為例子)程式碼:
package Thread; class Tickets implements Runnable{ private int ticket=100; Object obj = new Object(); public void run(){ while(ticket!=0) {//多執行緒裡要有迴圈 sale(); } } public synchronized void sale(){ if (ticket > 0) { //使CPU在這裡停一下,使用sleep()函式,Thread 中的靜態函式。使其出現錯誤的資料 try { Thread.sleep(10); } catch (InterruptedException e) { }//沒有解決方案 System.out.println(Thread.currentThread().getName() + " " + --ticket); } } } public class ThreadSellTickets { public static void main(String[] args){ Tickets tc = new Tickets(); Thread T1 =new Thread(tc); Thread T2 =new Thread(tc); // Thread T3 =new Thread(tc); //Thread T4 =new Thread(tc); T1.start(); T2.start(); //T3.start(); //T4.start(); } }
同步函式:用synchronized 修飾的函式,因為函式是被物件呼叫的,所以在使用同步函式時:this.函式名。
在函式呼叫時其實最完整的其實就是this.函式名
驗證寫法就是方法:(驗證同步函式的所是否為this)
開啟兩條執行緒,一條執行同步程式碼塊,一條執行同步函式,如果執行結果沒有錯誤,證明所用的物件/鎖 是一致的,如果執行出現了錯誤證明所用的物件不一致
程式碼:(完整正確的程式碼)
package Thread; class Ticket implements Runnable{ private int ticket=100; boolean flag=true; Object obj = new Object(); public void run(){ if(flag){ for(int x=1;x<=5;x++){ synchronized (this){ if(ticket>0){ try{Thread.sleep(10);}catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+" ticket = "+--ticket); } } } } else{ for(int y=1;y<=5;y++) { sale(); } } } public synchronized void sale(){ if(ticket>0){ try{Thread.sleep(10);}catch(InterruptedException e){} System.out.println(Thread.currentThread().getName()+" ticket = "+--ticket); } } } public class Differents { public static void main(String[] args){ Ticket t = new Ticket(); Thread T1 =new Thread(t); Thread T2 =new Thread(t); T1.start(); try{Thread.sleep(10);}catch(InterruptedException e){}//使主執行緒停一會此時只有執行緒0 在執行 t.flag=false; T2.start(); } }
關於這段程式碼的解釋:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
首先明確CPU切換的意思:CPU是切換到執行緒,CPU切換到那個執行緒,哪一個執行緒就往下執行(指哪裡,哪裡跑)
解釋執行緒開啟間加入休眠函式,避免執行緒0開啟後flag 立刻被改變,並且主執行緒開啟執行緒1
這段程式碼run 函式中換成無限迴圈更好理解這段程式碼:
flag = true ; 執行緒0 會一直執行同步程式碼塊,執行緒0 執行一段時間後,flag 被改變,執行緒1被開啟,執行緒1執行的是同步函式。
如果兩個鎖不一樣,當執行緒0執行同步程式碼塊中程式碼到一半時CPU切換到執行緒1,執行緒1 可以在同步函式中對共享資料進行修改——資料會出現錯誤。
如果兩個鎖(為this )是一樣的,執行緒0,執行同步程式碼塊執行到一半時CPU切換到執行緒1,執行緒一無法進入同步函式,因為鎖物件還線上程0那