1. 程式人生 > >Java多線程學習篇(二)synchronized

Java多線程學習篇(二)synchronized

參考 .get name syn his col 靜態方法 runtest 作用範圍

synchronized 有二種修飾方法:
  1. 修飾一個方法

    synchronized public void runTest{
        /**/
    }
  2. 修飾一個代碼塊

    public void runTest{
        synchronized( /*某一對象或某一類*/ ){
            /* 代碼塊 */
        }
    }
synchronized 的作用範圍分為修飾一個類和修飾一共對象
當修飾一個對象時,不同線程的同一對象調用相同代碼會發生堵塞
當修飾一個時,不同線程的同一類調用相同代碼會發生堵塞
修飾靜態方法相當於修飾類

定義一個類(用於驗證 synchronized 的作用範圍)

public
class Test implements Runnable { public static int Count = 0; @Override public void run() { runTest(); } public void runTest() { for (int i = 0; i < 5; ++i) { Count++; System.out.println(Thread.currentThread().getName() + " " + Count); } } }

當 synchronized 修飾一個方法時

  1. 若方法為非靜態方法,作用的範圍是一個對象

    不同線程的同一對象調用該方法時會發生堵塞

    //調用相同的對象
    synchronized public void runTest() { // 修飾非靜態的方法 for (int i = 0; i < 5; ++i) { Count++; System.out.println(Thread.currentThread().getName() + " " + Count); } }

    通過以下代碼調用

    Test test = new Test();
    Thread thread_one 
    = new Thread( test, "Thread_ONE" ); Thread thread_two = new Thread( test, "Thread_Two" ); thread_one.start(); thread_two.start();

    結果是

    Thread_ONE 1
    Thread_ONE 2
    Thread_ONE 3
    Thread_ONE 4
    Thread_ONE 5
    Thread_Two 6
    Thread_Two 7
    Thread_Two 8
    Thread_Two 9
    Thread_Two 10

    由於該調用是二個thread任務中的對象是同一個test,第一個thread任務運行時,會將第二個任務堵塞

    若對象不是同一個,則不會發生堵塞

    //調用二個不同的對象
    Thread thread_one = new Thread(new Test(), "Thread_ONE");
    Thread thread_two = new Thread(new Test(), "Thread_Two");
    thread_one.start();
    thread_two.start();

    結果是

    Thread_Two 2
    Thread_ONE 1
    Thread_Two 3
    Thread_ONE 4
    Thread_Two 5
    Thread_ONE 6
    Thread_Two 7
    Thread_ONE 8
    Thread_Two 9
    Thread_ONE 10

  2. 當修飾的方法為靜態的方法時,作用的範圍是一個類,而非一個對象。

    不同線程的相同類調用該方法時都會發生堵塞

    //調用相同的對象
    Test test = new Test();
    Thread thread_one = new Thread( test, "Thread_ONE" );
    Thread thread_two = new Thread( test, "Thread_Two" );
    thread_one.start();
    thread_two.start();
    
    //調用二個不同的對象
    Thread thread_one = new Thread(new Test(), "Thread_ONE");
    Thread thread_two = new Thread(new Test(), "Thread_Two");
    thread_one.start();
    thread_two.start();

    結果都為

    Thread_ONE 1
    Thread_ONE 2
    Thread_ONE 3
    Thread_ONE 4
    Thread_ONE 5
    Thread_Two 6
    Thread_Two 7
    Thread_Two 8
    Thread_Two 9
    Thread_Two 10

當 synchronized 修飾一個代碼塊時,作用的範圍看括號內的內容。若括號內為對象,則範圍是一個對象;若括號內為類,則範圍是一個類

  1. 若括號內為對象,則範圍是一個對象,效果和 synchronized 修飾非靜態方法一樣

    public void runTest() {
        synchronized (this) { // 括號內為一個對象
            for (int i = 0; i < 5; ++i) {
                Count++;
                System.out.println(Thread.currentThread().getName() + " " + Count);
            }
        }
    }

    效果

    //調用相同的對象
    Test test = new Test();
    Thread thread_one = new Thread( test, "Thread_ONE" );
    Thread thread_two = new Thread( test, "Thread_Two" );
    thread_one.start();
    thread_two.start();
    //發生類堵塞
    //Thread_ONE 1
    //Thread_ONE 2
    //Thread_ONE 3
    //Thread_ONE 4
    //Thread_ONE 5
    //Thread_Two 6
    //Thread_Two 7
    //Thread_Two 8
    //Thread_Two 9
    //Thread_Two 10
    
    
    //調用二個不同的對象
    Thread thread_one = new Thread(new Test(), "Thread_ONE");
    Thread thread_two = new Thread(new Test(), "Thread_Two");
    thread_one.start();
    thread_two.start();
    // 沒有發生堵塞
    //Thread_Two 2
    //Thread_ONE 1
    //Thread_Two 3
    //Thread_ONE 4
    //Thread_Two 5
    //Thread_ONE 6
    //Thread_Two 7
    //Thread_ONE 8
    //Thread_Two 9
    //Thread_ONE 10
  2. 若括號內為類,則範圍是一個對象,效果和 synchronized 修飾靜態方法一樣

    public [static] void runTest() {  
        synchronized (Test.class) { // 括號內為一個類
            for (int i = 0; i < 5; ++i) {
                Count++;
                System.out.println(Thread.currentThread().getName() + " " + Count);
            }
        }
    }

    二種調用都發生堵塞

    Thread_ONE 1
    Thread_ONE 2
    Thread_ONE 3
    Thread_ONE 4
    Thread_ONE 5
    Thread_Two 6
    Thread_Two 7
    Thread_Two 8
    Thread_Two 9
    Thread_Two 10

參考:http://tutorials.jenkov.com/java-concurrency/synchronized.html

Java多線程學習篇(二)synchronized