当你使用synchronized关键字去保护一个代码块时,你必须传入一个对象的引用。

正常来讲,你讲使用this关键字去引用执行这个方法的对象,但是你可以使用其他对象的引用。

通常的,这些对象将会是专有的。例如,如果多个线程共享一个类中有2个独立的属性,你必须对每个变量做读取同步操作,

但是如果一个线程读取一个属性而另一个线程读取另一个这个没问题的。

本例中,你讲学会如何解决这个问题。我们将模拟带有2块屏幕和2个售票窗口的电影院。

当一个售票窗口买票时,它卖出的肯定是其中某个播放厅的座位,这样一来每个厅的座位数就是独立的属性。

Cinema.java
package com.dylan.thread.ch2.c02.task;

public class Cinema {

	/**
* This two variables store the vacancies in two cinemas
*/
private long vacanciesCinema1;
private long vacanciesCinema2; /**
* Two objects for the synchronization. ControlCinema1 synchronizes the
* access to the vacancesCinema1 attribute and controlCinema2 synchronizes
* the access to the vacanciesCinema2 attribute.
*/
private final Object controlCinema1, controlCinema2; /**
* Constructor of the class. Initializes the objects
*/
public Cinema(){
controlCinema1=new Object();
controlCinema2=new Object();
vacanciesCinema1=20;
vacanciesCinema2=20;
} /**
* This method implements the operation of sell tickets for the cinema 1
* @param number number of tickets sold
* @return true if the tickets are sold, false if there is no vacancies
*/
public boolean sellTickets1 (int number) {
synchronized (controlCinema1) {
if (number<vacanciesCinema1) {
vacanciesCinema1-=number;
return true;
} else {
return false;
}
}
} /**
* This method implements the operation of sell tickets for the cinema 2
* @param number number of tickets sold
* @return true if the tickets are sold, false if there is no vacancies
*/
public boolean sellTickets2 (int number){
synchronized (controlCinema2) {
if (number<vacanciesCinema2) {
vacanciesCinema2-=number;
return true;
} else {
return false;
}
}
} /**
* This method implements the operation of return tickets for the cinema 1
* @param number number of the tickets returned
* @return true
*/
public boolean returnTickets1 (int number) {
synchronized (controlCinema1) {
vacanciesCinema1+=number;
return true;
}
} /**
* This method implements the operation of return tickets for the cinema 1
* @param number number of the tickets returned
* @return true
*/
public boolean returnTickets2 (int number) {
synchronized (controlCinema2) {
vacanciesCinema2+=number;
return true;
}
} /**
* Return the vacancies in the cinema 1
* @return the vacancies in the cinema 1
*/
public long getVacanciesCinema1() {
return vacanciesCinema1;
} /**
* Return the vacancies in the cinema 2
* @return the vacancies in the cinema 2
*/
public long getVacanciesCinema2() {
return vacanciesCinema2;
} }

TicketOffice1.java
package com.dylan.thread.ch2.c02.task;

/**
* This class simulates a ticket office. It sell or return tickets
* for the two cinemas
*
*/
public class TicketOffice1 implements Runnable { /**
* The cinema
*/
private Cinema cinema; /**
* Constructor of the class
* @param cinema the cinema
*/
public TicketOffice1 (Cinema cinema) {
this.cinema=cinema;
} /**
* Core method of this ticket office. Simulates selling and returning tickets
*/
@Override
public void run() {
cinema.sellTickets1(3);
cinema.sellTickets1(2);
cinema.sellTickets2(2);
cinema.returnTickets1(3);
cinema.sellTickets1(5);
cinema.sellTickets2(2);
cinema.sellTickets2(2);
cinema.sellTickets2(2);
} }
TicketOffice2
package com.dylan.thread.ch2.c02.task;

/**
* This class simulates a ticket office. It sell or return tickets
* for the two cinemas
*
*/
public class TicketOffice2 implements Runnable { /**
* The cinema
*/
private Cinema cinema; /**
* Constructor of the class
* @param cinema the cinema
*/
public TicketOffice2(Cinema cinema){
this.cinema=cinema;
} /**
* Core method of this ticket office. Simulates selling and returning tickets
*/
@Override
public void run() {
cinema.sellTickets2(2);
cinema.sellTickets2(4);
cinema.sellTickets1(2);
cinema.sellTickets1(1);
cinema.returnTickets2(2);
cinema.sellTickets1(3);
cinema.sellTickets2(2);
cinema.sellTickets1(2);
} }
Main.java
package com.dylan.thread.ch2.c02.core;

import com.dylan.thread.ch2.c02.task.Cinema;
import com.dylan.thread.ch2.c02.task.TicketOffice1;
import com.dylan.thread.ch2.c02.task.TicketOffice2; /**
* Core class of the example. Creates a cinema and two threads for
* the ticket office. Run the threads to analyze the results obtained
*
*/
public class Main { /**
* Main method of the example
* @param args
*/
public static void main(String[] args) {
// Creates a Cinema
Cinema cinema=new Cinema(); // Creates a TicketOffice1 and a Thread to run it
TicketOffice1 ticketOffice1=new TicketOffice1(cinema);
Thread thread1=new Thread(ticketOffice1,"TicketOffice1"); // Creates a TicketOffice2 and a Thread to run it
TicketOffice2 ticketOffice2=new TicketOffice2(cinema);
Thread thread2=new Thread(ticketOffice2,"TicketOffice2"); // Starts the threads
thread1.start();
thread2.start(); try {
// Waits for the finalization of the threads
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
} // Print the vacancies in the cinemas
System.out.printf("Room 1 Vacancies: %d\n",cinema.getVacanciesCinema1());
System.out.printf("Room 2 Vacancies: %d\n",cinema.getVacanciesCinema2());
} }

运行结果:

Room 1 Vacancies: 5
Room 2 Vacancies: 6

Java并发编程实例--14.在一个同步类中安排独立属性的更多相关文章

  1. Java并发编程:线程的同步

    Java并发编程:线程的同步 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #839496;} J ...

  2. Java并发编程的4个同步辅助类

    Java并发编程的4个同步辅助类(CountDownLatch.CyclicBarrier.Semphore.Phaser) @https://www.cnblogs.com/lizhangyong/ ...

  3. Java并发编程的4个同步辅助类(CountDownLatch、CyclicBarrier、Semphore、Phaser)

    我在<jdk1.5引入的concurrent包>中,曾经介绍过CountDownLatch.CyclicBarrier两个类,还给出了CountDownLatch的演示案例.这里再系统总结 ...

  4. Java并发编程的4个同步辅助类(CountDownLatch、CyclicBarrier、Semaphore、Phaser)

    我在<JDK1.5引入的concurrent包>中,曾经介绍过CountDownLatch.CyclicBarrier两个类,还给出了CountDownLatch的演示案例.这里再系统总结 ...

  5. Java并发编程(三)Thread类的使用

    一.线程的状态 线程从创建到最终的消亡,要经历若干个状态.一般来说,线程包括以下这几个状态:创建(new).就绪(runnable).运行(running).阻塞(blocked).time wait ...

  6. Java并发编程(六)-- 同步块

    上一节已经讲到,使用Synchronzied代码块可以解决共享对象的竞争问题,其实还有其他的方法也可以避免资源竞争问题,我统称他们为Java同步块.Java 同步块(synchronized bloc ...

  7. Java并发编程实例(synchronized)

    此处用一个小程序来说明一下,逻辑是一个计数器(int i):主要的逻辑功能是,如果同步监视了资源i,则不输出i的值,但如果没有添加关键字synchronized,因为是两个线程并发执行,所以会输出i的 ...

  8. Java并发编程(八)同步容器

    为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch) 一.为什么会出现同步容器? ...

  9. Java并发编程(二)同步

    在多线程的应用中,两个或者两个以上的线程需要共享对同一个数据的存取.如果两个线程存取相同的对象,并且每一个线程都调用了修改该对象的方法,这种情况通常成为竞争条件.  竞争条件最容易理解的例子就是:比如 ...

  10. [转]JAVA并发编程学习笔记之Unsafe类

    1.通过Unsafe类可以分配内存,可以释放内存:类中提供的3个本地方法allocateMemory.reallocateMemory.freeMemory分别用于分配内存,扩充内存和释放内存,与C语 ...

随机推荐

  1. [转帖]如何查看Docker容器环境变量,如何向容器传递环境变量

    https://www.cnblogs.com/larrydpk/p/13437535.html 1 前言 欢迎访问南瓜慢说 www.pkslow.com获取更多精彩文章! 了解Docker容器的运行 ...

  2. [转帖]9.1 TiDB HTAP 的特点

    HTAP 是 Hybrid Transactional / Analytical Processing 的缩写.这个词汇在 2014 年由 Gartner 提出.传统意义上,数据库往往专为交易或者分析 ...

  3. [转帖]【基础】HTTP、TCP/IP 协议的原理及应用

    https://juejin.cn/post/6844903938232156167 前言 本文将持续记录笔者在学习过程中掌握的一些 HTTP .TCP/IP 的原理,以及这些网络通信技术的一些应用场 ...

  4. [转帖]拜托!面试请不要再问我Spring Cloud底层原理

    https://www.cnblogs.com/jajian/p/9973555.html 概述# 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大 ...

  5. MYSQL 日志参数与性能的关系

    1. 先看一下mysql技术内幕 innodb存储引擎的一个结果 以及各个参数的含义

  6. linux root用户密码输入正确还是提示access denied

    问题:之前用远程工具连接一直都是好的,第二天上班找开远程工具要输root的密码了,输入用户密码后还是无效,可以确定用户密码是对的,其中有一个远程工具一直是连着的就没有问题. 排查问题: 1.相接用pa ...

  7. Go泛型简介

    Go语言的泛型是在Go 1.18版本中引入的一个新特性,它允许开发者编写可以处理不同数据类型的代码,而无需为每种数据类型都编写重复的代码.以下是关于Go语言泛型的一些关键点: 泛型是通过在函数或类型定 ...

  8. vim 从嫌弃到依赖(15)——寄存器

    在计算机里面也有寄存器,计算机中的寄存器是看得见,摸得着的实体,寄存器中存储需要经常访问的一些数据.而vim中也有寄存器的概念,vim中的寄存器是一个虚拟的概念,更像是一块专门用来存储数据的内存缓冲区 ...

  9. C++ LibCurl实现Web隐藏目录扫描

    LibCurl是一个开源的免费的多协议数据传输开源库,该框架具备跨平台性,开源免费,并提供了包括HTTP.FTP.SMTP.POP3等协议的功能,使用libcurl可以方便地进行网络数据传输操作,如发 ...

  10. C/C++ 提权与强制卸载DLL

    权限提升 #include <Windows.h> #include <stdio.h> BOOL SetPrivilege(LPCTSTR lpszPrivilege, BO ...