1. 程式人生 > >Java線程同步操作

Java線程同步操作

tint cep @override blog account 時間 span 靜態方法 rfi

synchronized

作用於對象實例:對給定對象加鎖,進入同步代碼前要獲得給定對象的鎖。

作用於實例方法:相當於對當前實例加鎖,進入同步代碼前要獲得當前實例的鎖。

作用於靜態方法:相當於對當前類加鎖,進入同步代碼前要獲得當前類的鎖。

使用

給實例對象加鎖

public class AccountingSync implements Runnable {
    static AccountingSync instance = new AccountingSync();
    static int i = 0;

    @Override
    public void run() {
        for
(int k = 0; k < 10000; k++) { synchronized (instance) { i++; } } } @Test public void testInteger() throws InterruptedException { int count = 10; Thread[] ts = new Thread[count]; for (int k = 0; k < count; k++) { ts[k] = new
Thread(instance); } // start for (int k = 0; k < count; k++) { ts[k].start(); } // join for (int k = 0; k < count; k++) { ts[k].join(); } System.out.println(i); } }

給類方法加鎖

public class AccountingSync2 implements
Runnable { static AccountingSync2 instance = new AccountingSync2(); static int i = 0; public synchronized void increase() { i++; } @Override public void run() { for (int k = 0; k < 10000; k++) { increase(); } } @Test public void testInteger() throws InterruptedException { int count = 10; Thread[] ts = new Thread[count]; for (int k = 0; k < count; k++) { ts[k] = new Thread(instance); } // start for (int k = 0; k < count; k++) { ts[k].start(); } // join for (int k = 0; k < count; k++) { ts[k].join(); } System.out.println(i); } }

給類方法加鎖的錯誤演示

public class AccountingSyncBad implements Runnable {
    static int i = 0;

    public synchronized void increase() {
        i++;
    }

    @Override
    public void run() {
        for (int k = 0; k < 10000; k++) {
            increase();
        }
    }

    @Test
    public void testInteger() throws InterruptedException {
        int count = 10;
        Thread[] ts = new Thread[count];

        for (int k = 0; k < count; k++) {
            ts[k] = new Thread(new AccountingSyncBad());
        }

        // start
        for (int k = 0; k < count; k++) {
            ts[k].start();
        }

        // join
        for (int k = 0; k < count; k++) {
            ts[k].join();
        }

        System.out.println(i);
    }
}

假設把給類實例加鎖中的每個實例比作一個門,上面的測試方法中每個門都有鎖但是10個門10把鎖,每個線程進一個門。還是不能保證臨界區資源i同時只一個線程訪問

fix

@Test
public void testIntegerFix() throws InterruptedException {
  int count = 10;
  AccountingSyncBad instance = new AccountingSyncBad();
  Thread[] ts = new Thread[count];

  for (int k = 0; k < count; k++) {
    ts[k] = new Thread(instance);
  }

  // start
  for (int k = 0; k < count; k++) {
    ts[k].start();
  }

  // join
  for (int k = 0; k < count; k++) {
    ts[k].join();
  }

  System.out.println(i);
}

給靜態類方法加鎖

public class AccountingSyncClass implements Runnable {
    static int i = 0;

    public static synchronized void increase() {
        i++;
    }

    @Override
    public void run() {
        for (int k = 0; k < 10000; k++) {
            increase();
        }
    }

    @Test
    public void testInteger() throws InterruptedException {
        int count = 10;
        Thread[] ts = new Thread[count];

        for (int k = 0; k < count; k++) {
            ts[k] = new Thread(new AccountingSyncClass());
        }

        // start
        for (int k = 0; k < count; k++) {
            ts[k].start();
        }

        // join
        for (int k = 0; k < count; k++) {
            ts[k].join();
        }

        System.out.println(i);
    }
    
    @Test
    public void testIntegerFix() throws InterruptedException {
        int count = 10;
        AccountingSyncClass instance = new AccountingSyncClass();
        Thread[] ts = new Thread[count];

        for (int k = 0; k < count; k++) {
            ts[k] = new Thread(instance);
        }

        // start
        for (int k = 0; k < count; k++) {
            ts[k].start();
        }

        // join
        for (int k = 0; k < count; k++) {
            ts[k].join();
        }

        System.out.println(i);
    }
}

上面測試的testInteger方法和testIntegerFix方法都能得到正確的結果,原因是給靜態類方法加鎖相當於10個門用的同一把鎖,保證了同一時間只有一個線程能訪問臨界區資源i。

Java線程同步操作