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