1. 程式人生 > >Java多執行緒中的物件互斥鎖

Java多執行緒中的物件互斥鎖

1、為什麼會有鎖?

在看執行緒同步的問題之前,我們先看一個生活中的小例子:
我拿著銀行卡去ATM取錢,假如我的卡里有3000塊,我要取走2000,這個時候,ATM會去銀行的資料庫裡查詢我的賬戶是否有2000以上的餘額,如果有,就會讓我取走,不幸的是,這個時候,我女朋友也來銀行取錢,只不過她在前臺取錢,她直接取走了3000,這個時候我的卡里已經沒錢了,而我也肯定也不能取出2000了。

我們可以這樣想,上面例子中的我和女朋友是兩個執行緒,我們在訪問同一塊資源,也就是一個賬戶,這個情況下,是不允許在一個執行緒訪問的時候,另一個執行緒來打斷的,就像我在取錢的時候,我女朋友是不能取的,不能打斷我。

我們先來看一段程式碼:

public class TestThread01 implements Runnable{

Timer timer = new Timer();
public static void main(String[] args) {
    TestThread01 t = new TestThread01();
    Thread t1 = new Thread(t);
    Thread t2 = new Thread(t);
    t1.setName("t1");
    t2.setName("t2");
    t1.start();
    t2.start();
}
public void run(){
    timer.add(Thread.currentThread().getName());
}
}
class Timer{
private static int num = 0;
public static void add(String name){
    num++;
    try {
        Thread.sleep(1);
    } catch (InterruptedException e) {

    }
    System.out.println(name +":你是第"+num+"使用timer的執行緒");
}
}

上面的程式碼我們就能看出兩個執行緒去訪問同一個資源,也就是timer的add方法,看一下執行結果:

t1:你是第2使用timer的執行緒
t2:你是第2使用timer的執行緒

結果為什麼是這樣呢?

我們分析一下:
t1啟動,訪問add方法,num++變為1,這時,t1睡眠,t2啟動,t2訪問add,num是1,++之後變為2,t2睡眠,t1再繼續訪問,列印“t1:你是第2使用timer的執行緒”,然後t1結束,t2繼續列印“t2:你是第2使用timer的執行緒”。

我們這就見到了執行緒的打斷,有的人可能會說是因為sleep了一毫秒,所以才會這樣,其實不然,如果沒有sleep,也有可能會被打斷,也有可能會正確執行。

2、物件互斥鎖的用法?

解決方法01:給可能競爭的資源物件加上互斥鎖,synchronized (this),鎖定當前物件。

class Timer{
private static int num = 0;
public void add(String name){
    synchronized (this) {
    num++;
    try {
        Thread.sleep(1);
    } catch (InterruptedException e) {

    }
    System.out.println(name +":你是第"+num+"使用timer的執行緒");
}
}
}

這時的執行結果:

 t1:你是第1使用timer的執行緒
 t2:你是第2使用timer的執行緒

解決方法02:給競爭的方法加上鎖

class Timer{
private static int num = 0;
public synchronized void add(String name){

    num++;
    try {
        Thread.sleep(1);
    } catch (InterruptedException e) {

    }
    System.out.println(name +":你是第"+num+"使用timer的執行緒");

}
}

結果也是對的。