Java中的同步与互斥机制--synchornized学习

     Java 关键字 synchronized Java 语言提供的对多线程和同步的一种机制。 synchronized 可以作为函数的修饰符,也可作为函数内的语句。它可以作用于 instance 变量,对象引用( object reference ), static 函数和类名称字面常量( class literals )。
下面介绍一下 synchronized 的关键字的使用方法:
一、 synchronized 作函数修饰符
public synchronized void fun()
{
     ……..
}
    fun() 就是一个同步方法,此时 synchronized 关键字锁定的是调用这个同步方法的对象。假设有 p1 p2 是同一个类的两个对象, p1 在不同的线程中运行会对 fun() 产生互斥和同步的效果;但是 p2 对象和 p1 对象互相不会对 fun() 产生同步和互斥作用(当然,不同线程中的 p2 对象的 fun() 还是有同步和互斥)。
对于非 static 的情况, synchronized 是对象级别的,其实质是将 synchronized 作用于对象引用( object reference )上,即拿到 p1 对象锁的线程,对 p1 fun() 方法有同步互斥作用,不同的对象之间坚持“和平共处”。因此,上面的代码等同于:
public void fun()
{
   synchronized(
this )   // this指的是调用这个方法的对象
   {
       ……
   }
}

二、 synchronized 同步程序块
public void fun_1(someObject obj)
{
  
synchronized (obj)
   {
       ……
   }
}
上面代码中,锁住的是 obj 对象(正如前面说的,对于非 static 的情况, sysnchronized 是对象级别的),谁拿到这个锁,谁就可运行 obj 控制的那段代码。通常情况,如果我们知道对用哪个对象作为锁时,就可以像上面的代码块一样使用 synchronized 。假如没有明确的对象作为锁,程序员又希望同步一段代码块,就可以使用下面的 trick
class Test implements Runnable
{
  
private byte [] lock = new byte [ 0 ];   // 定一个instance变量
   public void fun_2()
   {
      
synchronized (lock)
       {
           ……
       }
   }
}
在上面的代码示例中,定义了一个特殊的 instance 变量作为锁,这个 instance 变量必须是一个对象。定义 lock 为长度为 0 的数组对象是最佳方案。在编译后的字节码中,生成长度为 0 byte[] 只需要三条操作码。假如我们用所有类的超类 Object 来作锁,需要生成七条操作码。
[ 注意: ] 如果需要定义特殊的 instance 变量作为锁,最好将其定义为 private 的,同时定义其 get() 方法(如果使用自己定义的类的对象作为锁)。如果变量是 public 的,其他类的对象可以得到这个锁的控制权,并修改这个锁。这是非常不安全的。
[ 注意: ] 如果 instance 变量是一个对象,如数组或 ArrayList 什么的,那上述方法仍然不安全,因为当外界对象通过 get 方法拿到这个 instance 对象的引用后,又将其指向另一个对象,那么这个 private 变量也就变了,岂不是很危险。这个时候就需要将 get 方法也加上 synchronized 同步,并且,只返回这个 private 对象的 clone()―― 这样,调用端得到的就是对象副本的引用了。
三、 synchronized 修饰 static 方法
    synchronized 静态 (static) 方法的用法如下面代码示例:
public static synchronized void fun_3()
{
     ……
}
如果方法用 static 修饰, synchronized 的作用范围就是 class 一级的,它对类的所有对象起作用。像第一点中的 fun() 方法,如果是 static 的,那么 synchronized p1 对象和 p2 对象都起到同步互斥的作用。
其实说白了,对于 static synchronize 也可以理解为对象级别的( hoho !是不是有点糊涂了? ^_^ ),因此下面代码可以达到同样效果:
class XX
{
    
public static void fun_4()
     {
    
synchronized (XX. class )
     {
         ……
     }
     }
}
请注意, XX.class 也是一个对象,类型是 Class ,在一个 ClassLoader 里,它是唯一的。因此,我在前面说,也理解它是对象级别的。
最后简单总结一下:
<!--[if !supportLists]--> (1)     通常把 synchronized 关键字的作用范围划分为类的范围和对象的范围两种,不过偶个人理解的是,既然取得的锁都是对象(参考第三点),也可以认为 synchronized 关键字都作用于对象。 <!--[endif]-->
<!--[if !supportLists]--> (2)     synchronized 关键字是不能继承的,即,父类的 synchronized 方法在子类中不是 synchronized ,必须要重新的显式的声明为 synchronized 才行。 <!--[endif]-->

<!--[if !supportLists]-->(3)     实现同步需要很大的系统开销,导致延迟等待,甚至可能造成死锁,所以在非多线程情况下不要使用。<!--[endif]-->

转自: http://blog.csdn.net/lazy_tiger/archive/2007/10/11/1820582.aspx

你可能感兴趣的:(Java中的同步与互斥机制--synchornized学习)