Java 实现互斥和同步的机制

Java提供了关键字synchronized,这Java 语言提供的多线程互斥的一种机制。synchronized可以作为函数的修饰符,也可作为函数内的语句块。作用于对象引用(object reference

synchronized的关键字的使用方法有以下几种:

一、synchronized作函数修饰符public synchronized void fun()
{
    // write code here.
}
  

  fun()就是一个互斥的方法,此时synchronized关键字锁定的是当前方法所属的对象。假设有p1p2是同一个类的两个对象,当不同的线程调用访问p1的fun方法时,会产生互斥同步效果;但是不同线程调用p1的fun方法和p2的fun方法,两者无互斥同步效果 

synchronized是对象级别的,其实质是将synchronized作用于对象引用(object reference)上,即拿到p1对象锁的线程,执行方法体内容,其他的线程等待,直到执行线程执行完成方法体,不同的线程上调用不同的对象则无互斥同步效果(因为对象不同,所以线程得到的是不同的对象锁)。因此,上面的代码等同于:

public void fun()

{
  synchronized(
this)  // this指的是调用这个方法的对象
  {
     //code here
  }
}

二、synchronized同步程序块

public void fun_1(someObject obj)
{
  
synchronized(obj)
  {
      //code here
  }
}
  上面代码中,获得了obj对象的锁,拿到了这个锁,就可运行synchronized 代码块内的代码。通常情况,如果我们知道对用哪个对象作为锁时,就可以像上面的代码块一样使用synchronized。假如没有明确的对象作为锁,程序员又希望同步一段代码块,就可以使用下面的trick

class Test implements Runnable
{
  
private byte[] lock = new byte[0];  // 定一个instance变量
  public void fun_2()
  {
      
synchronized(lock)
      {
          ……
      }
  }
}
  在上面的代码示例中,定义了一个特殊的instance变量作为锁,这个instance变量必须是一个对象。定义lock为长度为0的数组对象是最佳方案。在编译后的字节码中,生成长度为0byte[]只需要三条操作码。假如我们用所有类的超类Object来作锁,需要生成七条操作码。[注意:]如果需要定义特殊的instance变量作为锁,最好将其定义为private的,同时定义其get()方法(如果使用自己定义的类的对象作为锁)。如果变量是public的,其他类的对象可以得到这个锁的控制权,并修改这个锁。这是非常不安全的。[注意:如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。

三、synchronized修饰static方法    

synchronized 静态(static)方法的用法如下面代码示例:

public static synchronized void fun_3()
{
   //code here
}
  

如果方法用static修饰,synchronized的作用范围就是该方法所属class 的类对象,它对类的所有实例对象起作用。像第一点中的fun()方法,如果是static的,那么synchronizedp1对象和p2对象都起到同步互斥的作用。因此下面代码可以达到同样效果:

class XX
{
    
public static void fun_4()
    {
    
synchronized(XX.class)
    {
       //code here
    }
    }
}
  请注意,XX.class也是一个对象,类型是Class,在一个ClassLoader里,它是唯一的。因此,我在前面说,也理解它是对象级别的。  

最后简单总结一下:

(1)    synchronized关键字都作用于对象。

(2)     synchronized关键字是不能继承的,即,父类的synchronized方法在子类中不是synchronized,必须要重新的显式的声明为synchronized才行。

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

转载于:https://my.oschina.net/mylingcc/blog/261777

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>