執行緒同步(執行緒安全處理Synchronized)與死鎖
阿新 • • 發佈:2019-01-10
一 執行緒同步
java中提供了執行緒同步機制,它能夠解決上述的執行緒安全問題。
執行緒同步的方式有兩種:
方式1:同步程式碼塊
方式2:同步方法
1 同步程式碼塊
同步程式碼塊: 在程式碼塊宣告上 加上synchronized
synchronized (鎖物件) { 可能會產生執行緒安全問題的程式碼 }
同步程式碼塊中的鎖物件可以是任意的物件;但多個執行緒時,要使用同一個鎖物件才能夠保證執行緒安全。
使用同步程式碼塊,對電影院賣票案例中Ticket類進行如下程式碼修改
package com.oracle.demo01; public class Myticket implements Runnable { private int ticket=100; private Object obj=new Object(); public void run() { while(true){ synchronized (obj) { if(ticket>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"出售第"+ticket--+"張票"); } } } } }
執行結果為:
這樣就解決了執行緒安全的問題
2 同步方法
同步方法:在方法宣告上加上synchronized
public synchronized void method(){ 可能會產生執行緒安全問題的程式碼 }
同步方法中的鎖物件是 this
使用同步方法,對電影院賣票案例中Ticket類進行如下程式碼修改:
package com.oracle.demo01; public class Myticket2 implements Runnable { private int ticket=100; //同步方法是否有鎖物件?有 this //靜態同步方法有鎖物件?有,MyTicket2.class //同步怎麼保證安全性?沒有鎖的執行緒不能執行只能等 //加了同步,執行緒進同步判斷鎖的時候,比如,獲取鎖,釋放鎖,導致執行速度慢 //StringBuilder比StringBuffer快的原因 //StringBuffer裡面的所有方法都加了同步關鍵字,所以慢,但安全 //StringBuilder是沒有的,所以快,但不安全 public synchronized void sale(){ //可能會產生執行緒安全問題的程式碼 if(ticket>0){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"出售第"+ticket--+"張票"); } } public void run() { while(true){ sale(); } } }
二 死鎖
同步鎖使用的弊端:當執行緒任務中出現了多個同步(多個鎖)時,如果同步中嵌套了其他的同步。這時容易引發一種現象:程式出現無限等待,這種現象我們稱為死鎖。這種情況能避免就避免掉。
package com.oracle.demo02; public class DeadLock implements Runnable { private int i=0; public void run() { while(true){ if(i%2==0){ //先進A同步,再進B同步 synchronized (LockA.locka) { System.out.println("if...locka"); synchronized (LockB.lockb) { System.out.println("if...lockb"); } } }else{ //先進B同步,再進A同步 synchronized (LockB.lockb) { System.out.println("else...lockb"); synchronized (LockA.locka) { System.out.println("else...locka"); } } } i++; } } }
程式無線等待