使用 Java 在线程之间传输数据

2024-01-05

我正在编写一个模仿电影院的多线程应用程序。每个参与的人都是自己的线程,并发必须完全由信号量来完成。我遇到的唯一问题是如何基本上链接线程以便它们可以通信(例如通过管道)。

例如:

Customer[1] 是一个线程,它获取一个信号量,让它走到票房。现在,客户[1] 必须告诉票房代理他们想看电影“X”。然后 BoxOfficeAgent[1] 也是一个线程,必须检查以确保电影未满,然后出售门票或告诉 Customer[1] 选择另一部电影。

如何来回传递数据,同时仍保持与信号量的并发性?

另外,我可以从 java.util.concurrent 使用的唯一类是信号 http://download.oracle.com/javase/6/docs/api/index.html?java/util/concurrent/Semaphore.html class.


在线程之间来回传递数据的一种简单方法是使用接口的实现BlockingQueue<E> http://download.oracle.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html,位于包中java.util.concurrent http://download.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html.

该接口具有以不同行为向集合添加元素的方法:

  • add(E): 如果可能的话添加,否则抛出异常
  • boolean offer(E): 如果元素已添加则返回 true,否则返回 false
  • boolean offer(E, long, TimeUnit):尝试添加元素,等待指定的时间
  • put(E):阻塞调用线程,直到添加元素为止

它还定义了具有类似行为的元素检索方法:

  • take(): 阻塞直到有可用元素
  • poll(long, TimeUnit): 检索一个元素或返回 null

我最常使用的实现是:ArrayBlockingQueue http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ArrayBlockingQueue.html, LinkedBlockingQueue http://download.oracle.com/javase/6/docs/api/java/util/concurrent/LinkedBlockingQueue.html and SynchronousQueue http://download.oracle.com/javase/6/docs/api/java/util/concurrent/SynchronousQueue.html.

第一个,ArrayBlockingQueue,具有固定大小,由传递给其构造函数的参数定义。

第二,LinkedBlockingQueue,大小不受限制。它总是接受任何元素,即offer将立即返回true,add永远不会抛出异常。

第三个,对我来说也是最有趣的一个,SynchronousQueue,实际上是一个管道。您可以将其视为大小为 0 的队列。它永远不会保留元素:只有当有其他线程尝试从中检索元素时,该队列才会接受元素。相反,如果有另一个线程尝试推送某个元素,则检索操作只会返回该元素。

为了履行homework的要求专门使用信号量进行同步,您可以从我给您提供的有关 SynchronousQueue 的描述中获得启发,并编写一些非常相似的内容:

class Pipe<E> {
  private E e;

  private final Semaphore read = new Semaphore(0);
  private final Semaphore write = new Semaphore(1);

  public final void put(final E e) {
    write.acquire();
    this.e = e;
    read.release();
  }

  public final E take() {
    read.acquire();
    E e = this.e;
    write.release();
    return e;
  }
}

请注意,此类呈现的行为与我所描述的 SynchronousQueue 类似。

一旦方法put(E)被调用时它会获取写入信号量,该信号量将保留为空,以便对同一方法的另一个调用将在其第一行阻塞。然后,此方法存储对正在传递的对象的引用,并释放读取的信号量。此版本将使任何线程都可以调用take()方法继续进行。

第一步take()然后,方法自然是获取读取信号量,以禁止任何其他线程同时检索该元素。检索元素并将其保存在局部变量中后(练习:如果删除那行 E e = this.e 会发生什么?),该方法释放写信号量,使得该方法put(E)可以由任何线程再次调用,并返回已保存在局部变量中的内容。

作为一个重要的评论,请注意对正在传递的对象的引用保存在私人领域,以及方法take() and put(E)都是final。这是极其重要的,但也常常被忽视。如果这些方法不是最终的(或更糟糕的是,该字段不是私有的),继承类将能够改变take() and put(E)违反合同。

最后,您可以避免在中声明局部变量的需要take()方法通过使用try {} finally {}如下:

class Pipe<E> {
  // ...
  public final E take() {
    try {
      read.acquire();
      return e;
    } finally {
      write.release();
    }
  }
}

在这里,这个例子的目的只是为了展示try/finally缺乏经验的开发人员不会注意到这一点。显然,在这种情况下,没有真正的收益。

哦该死,我已经帮你完成大部分作业了。为了报应——并且为了测试你对信号量的了解——,为什么不实现 BlockingQueue 合约定义的一些其他方法呢?例如,您可以实现一个offer(E)方法和一个take(E, long, TimeUnit)!

祝你好运。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Java 在线程之间传输数据 的相关文章

随机推荐

  • 在 Feign 客户端中使用 spring 表单编码器时,请求正文未正确编码和隐藏

    我已经为 spring open feign 添加了必要的依赖项 如中提到的https github com OpenFeign feign form https github com OpenFeign feign form并遵循上述 f
  • 如何在两个表格之间添加垂直线?

    这是标记 我想在两个表格之间添加一条垂直线 我不想在这里使用图像 我需要一个纯 html 解决方案 div table width 50 tr td p class dotted row 1 cell 1 p td td p class d
  • PgAdmin 的 Kubernetes 持久卷挂载

    我正在尝试为我的 pgadmin 部署创建持久卷声明 以便在每次从 CD 管道部署后推出更新时可以保留我的设置 服务器等 在我的日志中 我收到以下错误 2020 10 05 00 54 56 0000 91 INFO Worker exit
  • Angular2:如何向应用程序注入没有装饰器的服务?

    当尝试使用时Http在 App 组件 我们正在引导的组件 中一切正常 找到 export default class AppComponent constructor public http Http console log this ht
  • 删除 MagicalRecord 中的实体不会持久

    我在使用 MagicalRecord 时遇到了一个奇怪的问题 删除不会持久 当我删除时 NSFetchedResultsControllerDelegate 正确地看到该对象已被删除 但是 如果我关闭并重新打开应用程序 该实体就会重新出现
  • Executor 上的 AsyncTask 和 PriorityBlockingQueue 实现问题

    在浪潮中这个问题 https stackoverflow com questions 12039596 asynctask on executor and priorityblockingqueue并有许多提示另一个 https stack
  • 测量计时器的精度(例如秒表/QueryPerformanceCounter)

    鉴于StopwatchC 中的类可以在下面使用三个不同的计时器 例如 系统定时器例如精度约 10 ms取决于可以设置的定时器分辨率timeBeginPeriod https msdn microsoft com en us library
  • plot.new尚未被调用

    为什么会发生这种情况 plot x y yx lm lt lm y x lines x predict yx lm col red 错误于plot xy xy coords x y type type plot new尚未被调用 某些操作
  • C# 解码(解压缩)PDF 文件的 Deflate 数据

    我想在 C 中解压缩一些 DeflateCoded 数据 提取的 PDF 不幸的是 我每次都会遇到异常 解码时发现无效数据 但数据是有效的 private void Decompress FileStream fs new FileStre
  • Number::toString() 抽象操作

    我试图理解如何数字 toString x https 262 ecma international org 11 0 sec numeric types number tostring抽象操作有效 据我所知 其要点似乎是非常大 n gt 2
  • exec 总是返回 -1 (或 127)

    我在生产服务器上使用 php 5 2 9 并且 exec 函数的行为似乎是 非标准 如果我跑exec ls output return var then output将按预期包含当前文件夹中的文件列表 但是 return var将被设置为
  • Google Spanner:JDBC 连接字符串?

    虽然 Spanner 看起来令人兴奋 但 Simba JDBC 驱动程序的文档 包含在此处的下载链接中 https cloud google com spanner docs partners drivers https cloud goo
  • 如何确保 slurm 中的 python 提交脚本位于发出 sbatch 命令的位置?

    我有一个运行的 python 提交脚本sbatch using slurm sbatch batch py 当我这样做时 事情无法正常工作 因为我认为 batch py进程没有继承正确的环境变量 因此 而不是运行batch py从哪里sba
  • 使用 Ruby 的 TracePoint 获取方法参数

    我可以使用 TracePoint API 访问 Ruby 方法的参数 def foo foo arg end trace TracePoint trace call c call do tp tp disable case tp metho
  • 在赋值 A(:) = B 中,A 和 B 中的元素数量必须相同

    例如 当尝试运行我的代码时 for ii 1 10 output ii rand 3 end 我收到错误 In an assignment A B the number of elements in A and B must be the
  • 目标 C:SHA1

    如何在 Objective c 中 sha1 一个字符串或一组数字 CommonCrypto Apple 框架 具有计算 SHA 1 哈希值的函数 包括一步哈希值 include
  • 给定 x、y 和色调,获取 HSL 值

    给定一个看起来像这样的颜色选择器 我正在尝试根据光标的 x 和 y 位置以及右侧滑块的色调来计算 HSL 值 我的数学技能相当薄弱 尽管我所拥有的很接近 但尝试获取真正浅的全强度颜色很麻烦 最终会变得太灰 这是我当前使用的功能 getHSL
  • C# 中使用反射进行方法拦截

    我编写了一个抽象类 它使用反射来查找构造函数中标有属性的字段 如下所示 AttributeUsage AttributeTargets Field public class TrackedField Attribute public cla
  • 定义频率上的音量 (C#)

    我不明白为什么音量定义的频率不符合预期 我依次将声音以几个指定的频率发送到麦克风 然后我对麦克风缓冲区进行 FFT 在 FFT 退出时 我有一个复数数组 要了解定义频率上的声音音量 我查看我的数组 该数组中的元素数量是这样得到的 MyFre
  • 使用 Java 在线程之间传输数据

    我正在编写一个模仿电影院的多线程应用程序 每个参与的人都是自己的线程 并发必须完全由信号量来完成 我遇到的唯一问题是如何基本上链接线程以便它们可以通信 例如通过管道 例如 Customer 1 是一个线程 它获取一个信号量 让它走到票房 现