Java線程安全synchronize學習

Java中,synchronized關鍵字有2種用法:java

  1. 做爲關鍵字修飾方法
  2. 修飾一個代碼塊

線程爭用

爲了探究synchronized的具體用法,能夠用一個簡單的程序來講明:dom

package fc.learn.java.synchronize;

import java.util.Random;

public class LearningSynchronized {

    public enum SyncTypeTag {
        OBJ_METHOD, CLASS_METHOD, KEYWARD_METHOD, NORMAL_METHOD
    }

    static class MyRunnable implements Runnable{

        private void counting(){
            for (int i = 0; i< 5; i++){
                System.out.println(String.format("Thread[%s] count for [%s]", Thread.currentThread().getName(), i));
                int sleepSeconds = new Random().nextInt();
                sleepSeconds = sleepSeconds % 10;
                sleepSeconds = sleepSeconds * sleepSeconds;
                sleepSeconds = sleepSeconds % 5;
                System.out.println(String.format("Thread[%s] sleep for 0.%s seconds", Thread.currentThread().getName(), sleepSeconds));
                try {
                    Thread.sleep(sleepSeconds * 100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        private void synchronizeObjectMethod() {
            synchronized (this){
                counting();
            }
        }

        private void synchronizeClasstMethod(){
            synchronized (MyRunnable.class){
                counting();
            }
        }

        private synchronized void synchronizedMethod(){
            counting();
        }


        private void normalMethod(){
            counting();
        }

        private SyncTypeTag synType;
        public MyRunnable(SyncTypeTag type){
            this.synType = type;
        }

        @Override
        public void run() {
            if (this.synType == SyncTypeTag.OBJ_METHOD) {
                synchronizeObjectMethod();
            } else if (this.synType == SyncTypeTag.CLASS_METHOD) {
                synchronizeClasstMethod();
            } else if (this.synType == SyncTypeTag.KEYWARD_METHOD) {
                synchronizedMethod();
            } else if (this.synType == SyncTypeTag.NORMAL_METHOD) {
                normalMethod();
            }
        }
    }

    public static void main(String[] args) {
        Runnable r1 = new MyRunnable(SyncTypeTag.NORMAL_METHOD);
        Runnable r2 = new MyRunnable(SyncTypeTag.NORMAL_METHOD);

        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);

        t1.start();
        t2.start();
    }

}

運行代碼,能夠得到結果以下:ide

Thread[Thread-1] count for [0]
Thread[Thread-0] count for [0]
Thread[Thread-1] sleep for 0.4 seconds
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-0] count for [1]
Thread[Thread-0] sleep for 0.4 seconds
Thread[Thread-1] count for [1]
Thread[Thread-1] sleep for 0.0 seconds
Thread[Thread-1] count for [2]
Thread[Thread-1] sleep for 0.1 seconds
Thread[Thread-1] count for [3]
Thread[Thread-0] count for [2]
Thread[Thread-1] sleep for 0.4 seconds
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-0] count for [3]
Thread[Thread-0] sleep for 0.4 seconds
Thread[Thread-1] count for [4]
Thread[Thread-1] sleep for 0.4 seconds
Thread[Thread-0] count for [4]
Thread[Thread-0] sleep for 0.1 seconds

也就是說,普通狀況下,counting()方法會被線程爭用this

類鎖 synchronized(class)

那麼咱們加鎖試試呢?首先試試對class加鎖:線程

// 以前代碼太多再也不贅述,此處只展現main方法
public static void main(String[] args) {
    Runnable r1 = new MyRunnable(SyncTypeTag.CLASS_METHOD);
    Runnable r2 = new MyRunnable(SyncTypeTag.CLASS_METHOD);

    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);

    t1.start();
    t2.start();
}

能夠獲得以下結果:code

Thread[Thread-0] count for [0]
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-0] count for [1]
Thread[Thread-0] sleep for 0.0 seconds
Thread[Thread-0] count for [2]
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-0] count for [3]
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-0] count for [4]
Thread[Thread-0] sleep for 0.4 seconds
Thread[Thread-1] count for [0]
Thread[Thread-1] sleep for 0.0 seconds
Thread[Thread-1] count for [1]
Thread[Thread-1] sleep for 0.0 seconds
Thread[Thread-1] count for [2]
Thread[Thread-1] sleep for 0.1 seconds
Thread[Thread-1] count for [3]
Thread[Thread-1] sleep for 0.1 seconds
Thread[Thread-1] count for [4]
Thread[Thread-1] sleep for 0.1 seconds

此時,線程再也不爭用,目的達到。orm

對象鎖 synchronized(object)

那麼試試對象鎖:htm

// 仔細觀察,這裏用的 this 也就是說,每一個線程用的不是同一把鎖
private void synchronizeObjectMethod() {
    synchronized (this){
        counting();
    }
}

public static void main(String[] args) {
    Runnable r1 = new MyRunnable(SyncTypeTag.CLASS_METHOD);
    Runnable r2 = new MyRunnable(SyncTypeTag.CLASS_METHOD);

    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);

    t1.start();
    t2.start();
}

運行代碼:對象

Thread[Thread-1] count for [0]
Thread[Thread-0] count for [0]
Thread[Thread-1] sleep for 0.0 seconds
Thread[Thread-0] sleep for 0.4 seconds
Thread[Thread-1] count for [1]
Thread[Thread-1] sleep for 0.1 seconds
Thread[Thread-1] count for [2]
Thread[Thread-1] sleep for 0.4 seconds
Thread[Thread-0] count for [1]
Thread[Thread-0] sleep for 0.4 seconds
Thread[Thread-1] count for [3]
Thread[Thread-1] sleep for 0.4 seconds
Thread[Thread-0] count for [2]
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-0] count for [3]
Thread[Thread-0] sleep for 0.0 seconds
Thread[Thread-0] count for [4]
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-1] count for [4]
Thread[Thread-1] sleep for 0.0 seconds

能夠發現,鎖並不起做用。這個緣由也很容易理解,由於synchronizeObjectMethod方法中用的synchronized(this)進行加鎖,而咱們有2個進程對象在對counting()方法進行操做,因此會發生爭用。若是代碼修改成這樣:

// synchronizedObjectMethod修改爲這樣:
private void synchronizeObjectMethod(Object globalLock) {
    synchronized (globalLock){
        counting();
    }
}
// 構造方法和成員變量:
private SyncTypeTag synType;
private Object globalLock;
public MyRunnable(SyncTypeTag type, Object lock){
    this.synType = type;
    this.globalLock = lock;
}

@Override
public void run() {
    if (this.synType == SyncTypeTag.OBJ_METHOD) {
        synchronizeObjectMethod(this.globalLock);
    } else if (this.synType == SyncTypeTag.CLASS_METHOD) {
        synchronizeClasstMethod();
    } else if (this.synType == SyncTypeTag.KEYWARD_METHOD) {
        synchronizedMethod();
    } else if (this.synType == SyncTypeTag.NORMAL_METHOD) {
        normalMethod();
    }
}

// main 方法:
public static void main(String[] args) {
    Object globalLock = new Object();
    Runnable r1 = new MyRunnable(SyncTypeTag.OBJ_METHOD, globalLock);
    Runnable r2 = new MyRunnable(SyncTypeTag.OBJ_METHOD, globalLock);

    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);

    t1.start();
    t2.start();
}

運行代碼:

Thread[Thread-0] count for [0]
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-0] count for [1]
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-0] count for [2]
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-0] count for [3]
Thread[Thread-0] sleep for 0.0 seconds
Thread[Thread-0] count for [4]
Thread[Thread-0] sleep for 0.0 seconds
Thread[Thread-1] count for [0]
Thread[Thread-1] sleep for 0.0 seconds
Thread[Thread-1] count for [1]
Thread[Thread-1] sleep for 0.4 seconds
Thread[Thread-1] count for [2]
Thread[Thread-1] sleep for 0.1 seconds
Thread[Thread-1] count for [3]
Thread[Thread-1] sleep for 0.1 seconds
Thread[Thread-1] count for [4]
Thread[Thread-1] sleep for 0.4 seconds

爭用消失。

關鍵字 synchronized method()

接下來再試試synchronized關鍵字直接修飾方法:

public static void main(String[] args) {
    Object globalLock = new Object();
    Runnable r1 = new MyRunnable(SyncTypeTag.KEYWARD_METHOD, globalLock);
    Runnable r2 = new MyRunnable(SyncTypeTag.KEYWARD_METHOD, globalLock);

    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);

    t1.start();
    t2.start();
}

運行代碼:

Thread[Thread-0] count for [0]
Thread[Thread-1] count for [0]
Thread[Thread-0] sleep for 0.0 seconds
Thread[Thread-1] sleep for 0.1 seconds
Thread[Thread-0] count for [1]
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-1] count for [1]
Thread[Thread-0] count for [2]
Thread[Thread-1] sleep for 0.1 seconds
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-0] count for [3]
Thread[Thread-0] sleep for 0.1 seconds
Thread[Thread-1] count for [2]
Thread[Thread-1] sleep for 0.4 seconds
Thread[Thread-0] count for [4]
Thread[Thread-0] sleep for 0.4 seconds
Thread[Thread-1] count for [3]
Thread[Thread-1] sleep for 0.4 seconds
Thread[Thread-1] count for [4]
Thread[Thread-1] sleep for 0.1 seconds

依舊會起爭用,說明synchronized修飾方法,等於 synchronized(this)

References:
http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966606.html

相關文章
相關標籤/搜索