在多线程中仅从LinkedList删除一次

时间:2018-06-27 18:27:19

标签: java multithreading linked-list

说我有一个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.使用请求的时间和streamNumber,我需要使用指向有效负载的指针(来自文件)。

最后,每个线程都会将有效载荷发送出去。因此,每个线程需要相同的信息,但响应会有所不同。发送有效负载后,它将抢占下一个请求的时间,并再次进行所有操作。

2 个答案:

答案 0 :(得分:1)

首先,当多个线程正在访问列表进行写操作时,LinkedList简直是一个糟糕的选择。您可以开始here来查找List接口的 other 实现,这些实现更适合此类需求。

正如您自己评论:另一个选择是将数据切片到单独的存储桶中,并将每个线程分配给不同的存储桶。哪种解决方案可以为您带来更好的结果,取决于您的确切要求。创建存储桶具有前期成本,而每次添加/删除元素时,线程安全队列都会使您付出成本。

另一种方法:

  • 只有一个列表,但没有5个线程在列表中移动
  • 相反,您依次迭代列表,然后对于每个循环迭代,获取一个列表条目,然后将5个任务对象推入某个ExecutorService实例中。

该服务之前已实例化,您可以基于ThreadPool或任何其他所需的东西(甚至是单个线程执行器,这对于单元测试也非常有用)。这样就增加了一些开销,因为您必须创建这些任务对象,但这会使其他一切都变得更加简单。

答案 1 :(得分:0)

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

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和message(标志等)将指示在给定的请求时间内任务发生了什么。感谢大家的投入!