Java中,synchronized關鍵字有2種用法:java
爲了探究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
那麼咱們加鎖試試呢?首先試試對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
那麼試試對象鎖: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關鍵字直接修飾方法:
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