1. 程式人生 > >執行緒同步(執行緒安全處理Synchronized)與死鎖

執行緒同步(執行緒安全處理Synchronized)與死鎖

一  執行緒同步

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++;
        }
    }
}

程式無線等待