在多线程中仅从链接列表中删除一次



假设我有一个填充 LinkedList 的对象,每个对象都存储我需要的相关信息。我有线程访问此列表的第一个元素以检索信息并对其执行一些操作,在操作结束时,我希望从列表中删除第一个元素。如何确保每个元素只调用一次 remove((?以便每个线程都可以访问列表中的相同下一个元素?

public class Test {
private static LinkedList<foo> list;
public static void main(String args[]) {
list = new LinkedList<>();
list.add(foo1);
list.add(foo2);
list.add(foo3);
for(int i = 0; i < 5; i++) {
new Thread(run()).start();
}
}
private static Runnable run() {
while(true) {
while(SomeCondition) {
//Do work.
}
list.remove();
}
}
}

我尝试为 remove 方法创建一个锁,但这会导致所有线程的每个元素之间出现明显的滞后。只有一个好主意吗

LinkedList<LinkedList<food>> mainList;

这样每个线程都有自己的列表可以工作?然后每个线程都可以这样做来访问他们的元素:

mainList.get(i).element();
mainList.get(i).remove();

编辑: 我没有提到main((有自己的线程,它不断地向列表中添加更多元素。主要目的是这是一个不断接收请求的服务器,请求作为"队列"放置在列表中。然后从 main(( 衍生出来的其他线程执行操作。请求的消息包含一个字段,该字段将让我知道哪个线程将执行什么操作。

编辑2: 我可能太模糊了,无法得到正确的答案,对不起!这是一个不断接收来自一个客户端的请求的服务器,列表中不断填充请求,为此目的最重要的字段是请求的时间:

for(int i = 0; i < 5; i++) {
new Thread(run(i)).start();
}
private static Runnable run(int streamNumber) {
while(true) {
while(SomeCondition) {
//Do work.
}
list.remove();
}
}

因此,streamNumber 指示以下内容: 1. 我要广播到哪个 IP 地址。 2. 使用请求的时间和流编号,哪个指针指向我需要使用的有效负载(来自文件(。

最后,每个线程将发送有效负载。因此,每个线程需要相同的信息,但响应会有所不同。一旦它发送了有效载荷,它将抓住下一个请求的时间并重新做所有事情。

首先,当多个线程访问列表以进行写入操作时,LinkedList只是一个糟糕的选择。您可以从这里开始,找到更适合此类需求的 List 接口的其他实现。

正如您自己评论的那样:另一种选择是将数据成单独的存储桶,并为每个线程分配一个不同的存储桶。哪种解决方案能为您提供更好的结果取决于您的确切要求。创建存储桶需要前期成本,而线程安全队列每次添加/删除元素时都会产生成本。

另一种方法:

  • 使用一个列表,但不要有 5 个线程遍历列表
  • 相反,您按顺序迭代列表,
  • 然后,对于每个循环迭代,您获取一个列表条目,然后将 5 个任务对象推送到某个 ExecutorService 实例中。

该服务之前已实例化,您可以将其基于ThreadPool或其他任何您想要的内容(甚至是单个线程执行器,这对于单元测试非常有用(。这会增加一些开销,因为您必须创建这些任务对象,但它使其他一切都变得简单得多。

我采用的解决方案是创建一个:

ExecutorService threadPool = Executors.newFixedThreadPool(5);
while(true) {
Request msg = new Request();
//Set data into msg via DataInputStream
for(int i = 0; i < 5; i++) {
threadPool.execute(stream(i, msg));
}
}
private Runnable stream(int streamNumber, Request msg) {
//Do some work.
}

我不是让 5 个线程使用 1 个列表并遇到复杂性,而是将 5 个任务推入池中。 streamNumber 和消息(标志等(将指示在给定请求的时间内任务会发生什么。感谢大家的投入!

最新更新