http://blog.csdn.net/fw0124/article/details/6672522
http://uule.iteye.com/blog/1488356
Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用.
对象锁:java的所有对象都含有1个互斥锁,这个锁由JVM自动获取和释放。线程进入synchronized方法的时候获取该对象的锁,当然如果已经有线程获取了这个对象的锁,那么当前线程会等待;synchronized方法正常返回或者抛异常而终止,JVM会自动释放对象锁。这里也体现了用synchronized来加锁的1个好处,方法抛异常的时候,锁仍然可以由JVM来自动释放。
类锁:对象锁是用来控制实例方法之间的同步,类锁是用来控制静态方法(或静态变量互斥体)之间的同步。其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。我们都知道,java类可能会有很多个对象,但是只有1个Class对象,也就是说类的不同实例之间共享该类的Class对象。Class对象其实也仅仅是1个java对象,只不过有点特殊而已。由于每个java对象都有1个互斥锁,而类的静态方法是需要Class对象。所以所谓的类锁,不过是Class对象的锁而已。获取类的Class对象有好几种,最简单的就是MyClass.class的方式。
package net.aty.lock.target; public class TargetMethod { // 对象锁:形式1 public synchronized void objLockMethod1() { System.out.println("in...objLockMethod1"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("out...objLockMethod1"); } // 对象锁:形式2 public void objLockMethod2() { synchronized (this) { System.out.println("in...objLockMethod2"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("out...objLockMethod2"); } } // 类锁:形式1 public static synchronized void classLock1() { System.out.println("classLock1------in"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("classLock1------out"); } // 类锁:形式2 public void classLock2() { synchronized (TargetMethod.class) { System.out.println("classLock2------in"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("classLock2------out"); } } }
测试:如果线程不存在数据共享,锁就不会有效果,也就没有必要加锁。
package net.aty.lock.thread.first; import net.aty.lock.target.TargetMethod; public class DemoThread1 extends Thread { private TargetMethod target = null; public DemoThread1(TargetMethod target) { this.target = target; } @Override public void run() { target.objLockMethod1(); } }
package net.aty.lock.thread.first; import net.aty.lock.target.TargetMethod; public class DemoThread2 extends Thread { private TargetMethod target = null; public DemoThread2(TargetMethod target) { this.target = target; } @Override public void run() { target.objLockMethod2(); } }
package net.aty.lock.thread.first; import net.aty.lock.target.TargetMethod; public class Test { public static void main(String[] args) throws Exception { test2(); } public static void test1() throws Exception { TargetMethod target1 = new TargetMethod(); TargetMethod target2 = new TargetMethod(); // 线程1运行后,睡眠500ms Thread t1 = new DemoThread1(target1); t1.start(); // 主线程睡眠100ms后,恢复执行,此时线程1仍然处于睡眠状态 Thread.sleep(100); System.out.println("main thread runnig...."); // 线程2开始运行 Thread t2 = new DemoThread2(target2); t2.start(); } public static void test2() throws Exception { TargetMethod shared = new TargetMethod(); Thread t1 = new DemoThread1(shared); t1.start(); Thread.sleep(100); System.out.println("main thread runnig...."); Thread t2 = new DemoThread2(shared); t2.start(); } }
package net.aty.lock.thread.second; import net.aty.lock.target.TargetMethod; public class DemoThread3 extends Thread { public DemoThread3() { } @Override public void run() { TargetMethod.classLock1(); } }
package net.aty.lock.thread.second; import net.aty.lock.target.TargetMethod; public class DemoThread4 extends Thread { private TargetMethod target = null; public DemoThread4(TargetMethod target) { this.target = target; } @Override public void run() { target.classLock2(); } }
package net.aty.lock.thread.second; import net.aty.lock.target.TargetMethod; public class Test { public static void main(String[] args) throws Exception { // 线程3运行后,睡眠500ms Thread t1 = new DemoThread3(); t1.start(); // 主线程睡眠100ms后,恢复执行,此时线程1仍然处于睡眠状态 Thread.sleep(100); System.out.println("main thread runnig...."); // 线程4开始运行 Thread t2 = new DemoThread4(new TargetMethod()); t2.start(); } }
classLock1------in
main thread runnig...
classLock1------out
classLock2------in
classLock2------out
最后测试下对象锁和类锁的区别和联系。线程5会访问同步的实例方法,线程6访问同步的静态方法。
package net.aty.lock.thread.third; import net.aty.lock.target.TargetMethod; public class DemoThread5 extends Thread { private TargetMethod target = null; public DemoThread5(TargetMethod target) { this.target = target; } @Override public void run() { target.objLockMethod1(); } }
package net.aty.lock.thread.third; import net.aty.lock.target.TargetMethod; public class DemoThread6 extends Thread { public DemoThread6() { } @Override public void run() { TargetMethod.classLock1(); } }
package net.aty.lock.thread.third; import net.aty.lock.target.TargetMethod; public class Test { public static void main(String[] args) throws Exception { test2(); } public static void test1() throws Exception { // 线程5开始运行 Thread t1 = new DemoThread5(new TargetMethod()); t1.start(); // 主线程睡眠100ms后,恢复执行,此时线程1仍然处于睡眠状态 Thread.sleep(100); System.out.println("main thread runnig...."); // 线程6运行后,睡眠500ms Thread t2 = new DemoThread6(); t2.start(); } public static void test2() throws Exception { // 线程6开始运行 Thread t2 = new DemoThread6(); t2.start(); // 主线程睡眠100ms后,恢复执行,此时线程1仍然处于睡眠状态 Thread.sleep(100); System.out.println("main thread runnig...."); // 线程5 Thread t1 = new DemoThread5(new TargetMethod()); t1.start(); } }
classLock1------in
main thread runnig....
in...objLockMethod1
classLock1------out
out...objLockMethod1
可以看出,类锁和对象锁不是同1个东西,一个是类的Class对象的锁,1个是类的实例的锁。也就是说:1个线程访问静态synchronized的时候,允许另一个线程访问对象的实例synchronized方法。反过来也是成立的,因为他们需要的锁是不同的。