最近在看Java Concurrent in Practice(java并发编程实践),发现自己对java的线程、锁等机制,理解很肤浅,学习的也不够全面。打算借着这本书,全面的学习下JDK的并发包和一些线程相关的理论知识,填补自己的空白,也可以和大家交流,理解不正确的地方,欢迎指正。第一篇博客,先简单的介绍下类锁和对象锁的概念,和关键字synchronized。

对象锁:java的所有对象都含有1个互斥锁,这个锁由JVM自动获取和释放。线程进入synchronized方法的时候获取该对象的锁,当然如果已经有线程获取了这个对象的锁,那么当前线程会等待;synchronized方法正常返回或者抛异常而终止,JVM会自动释放对象锁。这里也体现了用synchronized来加锁的1个好处,方法抛异常的时候,锁仍然可以由JVM来自动释放。

类锁:对象锁是用来控制实例方法之间的同步,类锁是用来控制静态方法(或静态变量互斥体)之间的同步。其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。我们都知道,java类可能会有很多个对象,但是只有1个Class对象,也就是说类的不同实例之间共享该类的Class对象。Class对象其实也仅仅是1个java对象,只不过有点特殊而已。由于每个java对象都有1个互斥锁,而类的静态方法是需要Class对象。所以所谓的类锁,不过是Class对象的锁而已。获取类的Class对象有好几种,最简单的就是MyClass.class的方式。

为什么需要加锁呢?肯定是因为存在不同线程对共享对象的并发访问,没有数据共享就不需要锁。

下面这个类,是我们使用java的synchronized方式进行控制的方法,会在我们后面的线程中调用。


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"         );        
                  }        
                  
                  }        
                  
         }



1、我们先来做第一个测试,该测试很简单,说明:如果线程不存在数据共享,锁就不会有效果,也就没有必要加锁。


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();        
                  }        
         }



2、第二组测试,验证所谓的"类锁"的确可以达到控制静态方法同步的效果


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();        
                  }        
                  
         }




执行结果如下:通过分析,可以知道的确实现了static方法之间的同步访问

classLock1------in
main thread runnig....
classLock1------out
classLock2------in
classLock2------out

3、最后我们来测试下对象锁和类锁的区别和联系。线程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方法。反过来也是成立的,因为他们需要的锁是不同的。