当前位置:嗨网首页>书籍在线阅读

03-方法同步

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

2.2 方法同步

本节将帮助你了解如何使用Java语言中最基本的同步方式之一,即使用 synchronized 关键词控制线程并发访问临界区方法或者代码块。在Java语言中,所有 synchronized 关键词(无论是作用在方法还是在代码块上的)都需要通过一个指向对象的引用来予以绑定,通过该绑定对象,一次只允许一个线程访问由同一个对象守护的方法或者代码块。

当你在方法中使用 synchronized 关键字时,对象引用是隐式的。当同一个对象实例上有多个方法都由 synchronized 关键词修饰时,只有一个执行线程可以访问这些方法。也就是说,如果此时有线程正在执行这批方法中的一个时,那么其他尝试访问相同对象实例上的任意 synchronized 方法的线程都将被挂起直到拿到访问权的线程完成了 synchronized 方法的执行。换句话说,每一个使用 synchronized 关键词声明的方法都是一个临界区,Java在同一时刻只允许一个线程执行对象临界区的代码。在这里, synchronized 所绑定的对象就是对象实例自身,也就是我们常说的 this 对象。静态方法跟普通的 synchronized 方法有所区别,需要特别注意的是,虽然静态的同步方法仅允许同时只有一个线程参与访问,但与此同时其他线程依然可以访问另一个由 synchronized 修饰的非静态方法。在这里,虽然两个线程都是访问同一个对象实例上的方法(其中一个是静态方法,而另一个不是),但是这两个方法却绑定了不同的对象。因此当通过这两个方法修改同一份共享数据时,可能会带来数据一致性的错误。造成该错误的原因是,当程序由 synchronized 修饰的静态方法调用时,此时方法所关联的对象是类对象而并非该类的实例对象。

synchronized 关键词保护代码块时,必须使用一个对象引用作为参数传入。通常使用 this 对象作为参数传入,但也可以传入其他对象,而这些其他对象一般是专门创建且不开放使用的。举个例子来说,假设此时有多个线程期望同时访问一个类中的两个独立的属性,那么开发者有必要保证在两个属性上的访问是线程同步的。有所例外的是,如果程序能够确保当前正在执行任务的两个线程只能访问不同的属性,则无须增加线程同步的限制。其他需要充分考虑的是,当 synchronized 关键词以对象本身(表示当前使用的是 this 关键词)作为参数时,其他同样以 this 作为参数传入 synchronized 的线程可能会因此受到影响。

本节将使用 synchronized 关键词完成一个模拟停车场的程序。在这个程序中,需要一个检测器,当一辆汽车或者摩托车驶入或者驶出停车场时,需要一个用于存储当前停车场内机动车停放数量的对象和一个用于存储现金流结果的对象。本节将会给出该程序的两种实现方式:一种没有任何同步机制保障,这时可以看看会有哪些错误结果出现;而另一种带有 synchronized 关键词的范例将会正确执行。