基本线程同步(三)在同步的类里安排独立属性

在同步的类里安排独立属性

当你使用synchronized关键字来保护代码块时,你必须通过一个对象的引用作为参数。通常,你将会使用this关键字来引用执行该方法的对象,但是你也可以使用其他对象引用。通常情况下,这些对象被创建只有这个目的。比如,你在一个类中有被多个线程共享的两个独立属性。你必须同步访问每个变量,如果有一个线程访问一个属性和另一个线程在同一时刻访问另一个属性,这是没有问题的。

在这个指南中,你将学习如何解决这种情况的一个例子,编程模拟一家电影院有两个屏幕和两个售票处。当一个售票处出售门票,它们用于两个电影院的其中一个,但不能用于两个,所以在每个电影院的免费席位的数量是独立的属性。

准备工作

这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。

如何做…

按以下步骤来实现的这个例子:

1.创建一个Cinema类,添加两个long类型的属性,命名为vacanciesCinema1和vacanciesCinema2。

1 public class Cinema {
2 private long vacanciesCinema1;
3 private long vacanciesCinema2;

2.给Cinema类添加两个额外的Object属性,命名为controlCinema1和controlCinema2。

1 private final Object controlCinema1, controlCinema2;

3.实现Cinema类的构造方法,初始化所有属性。

1 public Cinema(){
2 controlCinema1=new Object();
3 controlCinema2=new Object();
4 vacanciesCinema1=20;
5 vacanciesCinema2=20;
6 }

4.实现sellTickets1()方法,当第一个电影院出售一些门票将调用它。使用controlCinema1对象来控制访问synchronized的代码块。

01 public boolean sellTickets1 (int number) {
02 synchronized (controlCinema1) {
03 if (number<vacanciesCinema1) {
04 vacanciesCinema1-=number;
05 return true;
06 } else {
07 return false;
08 }
09 }
10 }

5.实现sellTickets2()方法,当第二个电影院出售一些门票将调用它。使用controlCinema2对象来控制访问synchronized的代码块。

01 public boolean sellTickets2 (int number) {
02 synchronized (controlCinema2) {
03 if (number<vacanciesCinema2) {
04 vacanciesCinema2-=number;
05 return true;
06 } else {
07 return false;
08 }
09 }
10 }

6.实现returnTickets1()方法,当第一个电影院被退回一些票时将调用它。使用controlCinema1对象来控制访问synchronized的代码块。

1 public boolean returnTickets1 (int number) {
2 synchronized (controlCinema1) {
3 vacanciesCinema1+=number;
4 return true;
5 }
6 }

7.实现returnTickets2()方法,当第二个电影院被退回一些票时将调用它。使用controlCinema2对象来控制访问synchronized的代码块。

1 public boolean returnTickets2 (int number) {
2 synchronized (controlCinema2) {
3 vacanciesCinema2+=number;
4 return true;
5 }
6 }

8.实现其他两个方法,用来返回每个电影院空缺位置的数量。

1 public long getVacanciesCinema1() {
2 return vacanciesCinema1;
3 }
4 public long getVacanciesCinema2() {
5 return vacanciesCinema2;
6 }

9.实现TicketOffice1类,并指定它实现Runnable接口。

1 public class TicketOffice1 implements Runnable {

10.声明一个Cinema对象,并实现该类(类TicketOffice1)的构造器用来初始化这个对象。

1 private Cinema cinema;
2 public TicketOffice1 (Cinema cinema) {
3 this.cinema=cinema;
4 }

11.实现run()方法,用来模拟在两个电影院的一些操作。

01 @Override
02 public void run() {
03 cinema.sellTickets1(3);
04 cinema.sellTickets1(2);
05 cinema.sellTickets2(2);
06 cinema.returnTickets1(3);
07 cinema.sellTickets1(5);
08 cinema.sellTickets2(2);
09 cinema.sellTickets2(2);
10 cinema.sellTickets2(2);
11 }

12.实现TicketOffice2类,并指定它实现Runnable接口。

1 public class TicketOffice2 implements Runnable {

13.声明一个Cinema对象,并实现该类(类TicketOffice2)的构造器用来初始化这个对象。

1 private Cinema cinema;
2 public TicketOffice2 (Cinema cinema) {
3 this.cinema=cinema;
4 }

14.实现run()方法,用来模拟在两个电影院的一些操作。

01 @Override
02 public void run() {
03 cinema.sellTickets2(2);
04 cinema.sellTickets2(4);
05 cinema.sellTickets1(2);
06 cinema.sellTickets1(1);
07 cinema.returnTickets2(2);
08 cinema.sellTickets1(3);
09 cinema.sellTickets2(2);
10 cinema.sellTickets1(2);
11 }

15.通过创建类名为Main,且包括main()方法来实现这个示例的主类。

1 public class Main {
2 public static void main(String[] args) {

16.声明和创建一个Cinema对象。

1 Cinema cinema=new Cinema();

17.创建一个TicketOffice1对象,并且用线程来运行它。

1 TicketOffice1 ticketOffice1=new TicketOffice1(cinema);
2 Thread thread1=new Thread(ticketOffice1,"TicketOffice1");

18.创建一个TicketOffice2对象,并且用线程来运行它。

1 TicketOffice2 ticketOffice2=new TicketOffice2(cinema);
2 Thread thread2=new Thread(ticketOffice2,"TicketOffice2");

19.启动这两个线程。

1 thread1.start();
2 thread2.start();

20.等待线程执行完成。

1 try {
2 thread1.join();
3 thread2.join();
4 } catch (InterruptedException e) {
5 e.printStackTrace();
6 }

21.两个电影院的空缺数写入控制台。

1 System.out.printf("Room 1 Vacancies: %d\n",cinema.getVacanciesCinema1());
2 System.out.printf("Room 2 Vacancies: %d\n",cinema.getVacanciesCinema2());

它是如何工作的…

当你使用synchronized关键字来保护代码块,你使用一个对象作为参数。JVM可以保证只有一个线程可以访问那个对象保护所有的代码块(请注意,我们总是谈论的对象,而不是类)。

注释:在这个示例中,我们用一个对象来控制vacanciesCinema1属性的访问。所以,在任意时刻,只有一个线程能修改该属性。用另一个对象来控制 vacanciesCinema2属性的访问。所以,在任意时刻,只有一个线程能修改这个属性。但是可能有两个线程同时运行,一个修改 vacancesCinema1属性而另一个修改vacanciesCinema2属性。

当你运行这个示例,你可以看到每个电影院的空缺数量的最后的结果总是预期的。在以下截图中,你可以看到应用程序的执行结果:

不止这些…

synchronize关键字还有其他重要用法,请见其他指南中解释这个关键字使用的参见部分。

参见

在第2章,基本线程同步中在同步代码中使用条件的指南。 

时间: 2024-10-31 09:47:39

基本线程同步(三)在同步的类里安排独立属性的相关文章

如何在普通类实例的线程过程中,同步调用执行在类实例自身所在的原来的那个线程中的方法

问题描述 如何在普通类实例的线程过程中,同步调用执行在类实例自身所在的原来的那个线程中的方法如后代码,是一个常见的实例,讲的是通过Control.Invoke在线程函数中,同步调用窗体主线程中的Form1实例的普通方法txt.但问题是,很多时候我们自己自定义的类,并不是从Control类继承的,从而也没有这个功能的Invoke方法供调用,这种类要怎么设计呢?虽然说用的示例代码是vb.net的,但严格来说,这个和语言无关,是一个.net开发的基本问题.ImportsSystemImportsSys

进程、线程知识点总结和同步(消费者生产者,读者写者三类问题)、互斥、异步、并发、并行、死锁、活锁的总结

进程和程序: 进程:是个动态的概念,指的是一个静态的程序对某个数据集的一次运行活动,而程序是静态的概念,是由代码和数据组成的程序块而已. 进程5大特点:动态性,并发性,独立运行性,异步性,和结构化的特性. 在多道程序环境下,程序不能独立运行,操作系统所有的特征都是基于进程而体现的,只有进程可以在系统中运行,程序运行必须有进程才行.进程是操作系统里资源分配的基本单位,也是独立运行的基本单位,具有动态的特点,暂时出现的特点,而且一个进程产生之后,可以再次生成多个进程出来.也可以多个进程并发执行,也可

JAVA之旅(十三)——线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this

JAVA之旅(十三)--线程的安全性,synchronized关键字,多线程同步代码块,同步函数,同步函数的锁是this 我们继续上个篇幅接着讲线程的知识点 一.线程的安全性 当我们开启四个窗口(线程)把票陆陆续续的卖完了之后,我们要反思一下,这里面有没有安全隐患呢?在实际情况中,这种事情我们是必须要去考虑安全问题的,那我们模拟一下错误 package com.lgl.hellojava; import javax.security.auth.callback.TextInputCallback

iOS中CoreData数据管理系列二——CoreData框架中三个重要的类

iOS中CoreData数据管理系列二--CoreData框架中三个重要的类 一.引言     在上一篇博客中,介绍了iOS中使用CoreData框架设计数据模型的相关步骤.CoreData框架中通过相关的类将数据--数据模型--开发者无缝的衔接起来.NSManagedObjectModel对应数据模型,即上篇博客中我们创建的.xcdatamodeld文件:NSPersistentStoreCoordinator相当于数据库与数据模型之间的桥接器,通过NSPersistentStoreCoord

java创建线程的三种方式及其对比

Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. (2)创建Thread子类的实例,即创建了线程对象. (3)调用线程对象的start()方法来启动该线程. package com.thread; public class FirstThreadTest extends Thread{ int i = 0; //重写run方法,run方法的方

Flash cs3仿真艺术设计5.6:图形元件的同步与不同步

本例为Flash CS3仿真艺术设计系列教程,在上二课中我们学习了运用交换法 和嵌套法制作嘴型吻合的技巧,今天我们来学习图形元件的同步与不同步,希望 通过本例的学习,能给朋友们带来帮助~~ 5.6 同步或不同步 用主时间轴同步一个嵌套在一个图形元件中的动画,在属面板选择同步选项. 当一个补间动画被应用时,同步是可以看见的.选择一个关键帧在属性面板中查 找同步选项,这个意思是嵌套的动画,嵌套的帧将被主时间轴同步.在这儿flash 制作同步特效稍微有点神秘:如果你从属性面板添加补间下拉菜单中应用补间

Flash cs3教程:图形元件的同步与不同步

  同步或不同步 用主时间轴同步一个嵌套在一个图形元件中的动画,在属面板选择同步选项.当一个补间动画被应用时,同步是可以看见的.选择一个关键帧在属性面板中查找同步选项,这个意思是嵌套的动画,嵌套的帧将被主时间轴同步.在这儿flash制作同步特效稍微有点神秘:如果你从属性面板添加补间下拉菜单中应用补间动画,那么同步未被限制,如果你在右键上下文菜单中应用补间动画,那么同步将被限制.同步特征表明在时间轴上一个关键帧被线性跟随.即是这样,那么你什么时候使用同步?什么时候不使用同步?让我们首先来看一个不使

python使用线程封装的一个简单定时器类实例

  本文实例讲述了python使用线程封装的一个简单定时器类.分享给大家供大家参考.具体实现方法如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from threading import Timer class MyTimer: def __init__(self): self._timer= None self._tm = None self._fn = N

百度云管家同步盘的同步文件夹是怎么回事?

  您在自己电脑上设置同步文件夹之后,百度云同步盘会实时监测这个文件夹里的文件,一旦同步盘发现用户对这些文件进行了操作,就会马上对网络硬盘中也进行同样的操作,保持网络硬盘中的文件与本地文件是一致的. 同样,如果您对网络硬盘中的文件进行了操作,同步盘也会马上对电脑上同步文件夹中的文件进行同样的操作.也就是说,在本地新建一个文件,网络硬盘中就自动新建一个完全一样的文件;本地修改,网络硬盘中就自动修改;本地删除,网络硬盘中就自动删除.反过来,在网络硬盘中所做的文件操作,也会被同步盘自动同步到本地电脑上