同步(1)

来源:互联网 发布:广州合优网络前端 编辑:程序博客网 时间:2024/05/22 14:58

在多线程中,某些公用资源会被多个线程同时使用,但是如果不同的线程对同一个资源使用完全相反的操作或是改变状态等操作,那么会导致资源数据或是状态的不正确变化,为了避免此类问题,java提出了同步机制。

synchronized

synchronized是java提供的关键字,常用来修饰函数及其内的语句,这也就是我们平时所说的同步方法和同步块。该关键字通过锁定公共资源来达到资源同步的效果,任何时刻都保证只有一个线程可以使用该资源,从而避免了资源的争夺。需要注意的是:

  • 无论synchronized关键字加在方法上还是对象上,他取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。 
  • 每个对象只有一个锁(lock)和之相关联。 
  • 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。

修饰函数

public synchronized void method(){……}


此时针对调用该函数的实例对象加锁,即对于同一个实例对象时,锁是起作用的。但是如果是同一个类的不同对象间,锁没有作用。这段代码等价于

public void method(){synchronized(this){……}}


这里就比较清楚的看到,锁是同对象关联的。当然锁也可以同类关联,如下:

public synchronized static void method(){……}


或是

public void method(){synchronized(ClassName.class){……}}


它们是同类关联的。但是注意

ClassName className = new ClassName();public void method(){synchronized(className.getClass()){……}}


className.getClass()做锁和ClassName.class做锁是不同的。这是由于对于ClassName.class来说锁是Object所属的那个Class,而 className.getClass()的锁是Object所属的这个对象。

修饰方法块

对于方法块来说需要找到它的锁对象,

public void method(ClassName className){synchronized(className){……}}


可以使用className对象作为锁,但是如果没有对象时,我们该怎么办呢?可以创建一个对象来作为锁

private byte[] lock = new byte[0];public void method(){synchronized(lock){……}}

变量

相对于同步方法和同步块来说,Collection变量更加需要同步处理。出于效率考虑,java.util包所属的Collection大多不是线程同步的。所幸java的工具类Collections提供了 synchronizedCollection、 synchronizedSet、 synchronizedSortedSet、 synchronizedList、 synchronizedMap、 synchronizedSortedMap方法,可以帮助我们将Collection变量对象转换为同步的。

原创粉丝点击