【问题标题】:Concurrent threads in Vector (Java)Vector(Java)中的并发线程
【发布时间】:2015-07-14 15:19:53
【问题描述】:

我正在设计一段多线程代码,其中包括查询多个传感器的部分(通过套接字),它们的数据首先存储在 Vector 中,然后写入 DB。

整个过程对时间敏感,因为每个传感器每隔几秒就会更新一次新数据。如果数据没有及时检索,就会丢失。 目前,我有一个(自定义传感器数据)类的向量,它存储从每个传感器获得的信息以及关于每个传感器的信息。

计划是为每个传感器打开一个线程(例如,总共 40-50,但不想限制数量,以防以后添加更多传感器)并让它访问并填充特定的(由向量的索引)向量的单元格。

对 Vector 进行这样的操作是否允许且谨慎?此外,了解 TCP/IP 套接字的特性后,我是否可能通过引入线程(而不是在单个线程中运行所有内容)来大幅加快进程?有没有更好或更优雅的方式来做到这一点?

【问题讨论】:

  • 计划是为每个传感器打开一个线程(例如,总共 40-50 个,但不想限制数量,以防以后添加更多传感器)不要那样做。创建许多线程 a) 昂贵且 b) 可能会降低系统速度。使用任务会更好。如果您有套接字,您可以创建一个任务来处理通信并将该任务放入ExecutorService(例如ThreadPoolExecutor
  • 传感器会写入哪些索引?它是向量中的索引所独有的吗?另请注意,最好不要使用 Java 的 Vector 类。 stackoverflow.com/questions/1386275/…
  • 这就是计划,是的。例如,在 Vector[1] 中包含有关 Sensor #1、Vector[2] ~ Sensor #2 等的信息。这是否意味着如果两个不同的线程尝试修改不同索引处的结构,则会引发异常?
  • 同时修改 ArrayList 是不安全的,我想这同样适用于 Vector 类。如果没有重叠索引,则使用普通数组是安全的,但在从其他线程读取数据之前,您仍然需要进行某种同步。在这种情况下,有 AtomicReferenceArray 类,但我不确定它是否适合这种情况,因为您会在旧条目保存到数据库之前丢失它们。

标签: java multithreading sockets vector tcp


【解决方案1】:

从您写的内容看来,Queue 更合适;您的线程将传感器数据推送到队列中,稍后(可能使用另一个线程)您可以从队列中获取元素并处理它们。 Java(至少版本 7 和 8)提供了一些不同的队列实现,即使在多线程环境中使用也是如此。 正如 Turing85 在他的评论中所写,考虑使用线程池而不是为每个传感器创建一个线程。

编辑:阅读评论似乎有两种不同的问题

如何有效地查询传感器(线程、任务、池等)

形成您似乎连接到传感器以读取数据的问题,并且必须以每个传感器的固定速率完成此操作。您可以使用ScheduledThreadPoolExecutor 并使用scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) 方法,其中 Runnable 是从传感器读取数据的对象;您必须为每个传感器安排一个任务;线程池大小在构造函数中指定。为了最小化线程数,您必须在读取数据的类中做的越少越好。我建议您将数据放入队列或地图或集合中,这取决于您的数据结构。该地图与您提出的向量相同,但您可以使用通用键来插入数据,而不是使用索引,并且您不关心集合的大小。

以及如何高效组织后续数据库的数据 提交

数据进入集合后,您可以读取和处理它们;您可以存储在数据库中,或检查重复项或您需要的任何内容。我更喜欢有两个不同的“层”,一个收集数据,另一个处理收集的数据;在两者之间放置一个“界面”可以让您的设计只发展一侧而不触及另一侧。

注意:我的解决方案允许您丢失数据,如果由于某种原因服务器出现故障,则集合中尚未处理的数据不再可用。

【讨论】:

  • 为什么要使用类似Queue 的东西,如果已经有实现来安排任务(参见my comment above)?
  • 因为它有点类似于海报的逻辑,一个任务(来自池的线程)收集数据并放入“容器”以供以后详细说明(存储但甚至其他)跨度>
  • 刚才看了一下队列。它能让我避免收集重复数据吗?也就是说,如果我从 Sensor1 将某些内容推送到队列,然后再将其他一些推送到队列中,则线程有可能在更改之前返回到 Sensor1。因此,它将重复数据推送到队列中。我可以对此进行检查,但您可能会看到在队列中进行此类检查比某些索引结构更难。如果我在这里遗漏了什么,请告诉我。
  • 向量和队列都允许重复,地图或集合可以让您更轻松地放置数据和管理唯一性
  • 如果重复项目是个问题,您可以保留队列并在另一端管理这些案例(我想是容器)。
【解决方案2】:

正如其他人建议的那样,我会使用 LinkedBlockingQueue,生产者是查询传感器并将数据存储在队列中的线程,消费者是将记录发送到数据库的线程。

线程模型取决于传感器的行为方式。如果您发出请求,但它在发送新数据之前没有响应,您可以安全地为每个传感器启动一个新线程。这将允许您编写简单的阻塞 I/O 代码并避免使用更复杂的方法。

确实,很多线程会减慢程序(甚至整个系统)的速度,但对于成千上万甚至数万个线程来说,这将是一个问题。此外,您的传感器每隔几秒提供一次数据,因此阅读器大部分时间都处于空闲状态。

【讨论】:

    【解决方案3】:

    对于任何感兴趣的人,我最终选择了 ConcurrentLinkedDequeue 来解决这个问题。它似乎拥有我需要的一切:队列属性和自动管理的并发。附:我也最终使用了 ThreadPool。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-06
      • 2021-12-12
      • 2023-03-22
      • 1970-01-01
      相关资源
      最近更新 更多