无法在javamultithreading中维护生产者任务的顺序

我正在编写一个multithreading应用程序,其中有一个生产者试图将一个元素添加到共享资源。 我想维护生产者在共享资源中生成元素的顺序。

例如,我的共享资源是SynchronizedQueue,P1,P2,P3,P4将以p1,p2,p3,p4的顺序生成新元素,在此期间P5生产者将其元素添加到队列中,因此P1, P2,P3,P4将等待锁定。 一旦P5释放锁定,P1-4中的任何一个都将获得锁定,因此我们会松开元素的顺序。

有没有办法维持等待锁定的元素的顺序? 根据我的理解,这是不可能的,但我想检查是否可以通过编程方式实现。

我能想到的一种方法是创建一个包装类, PriorityP具有int priorityP value字段。

然后为每个线程分配一个优先级( int ),并且线程给出一个具有适当优先级和值的PriorityP作为结果。

现在,您可以使用PriorityBlockingQueue而不是SynchronizedQueue ,并在PriorityP类中实现Comparator接口。

当你这样做时,每当一个线程将其值输入队列时,它就会自动放入正确的位置。

您没有提供任何代码来查看如何在共享资源上获取/释放锁,但您可能对java.util.concurrent.locks.ReentrantLock类感兴趣。

此类的构造函数接受可选的fairness参数。 当设置为true时,在争用下,锁定有利于授予对等待时间最长的线程的访问权限。

因此,如果P1,P2,P3尝试以该顺序获得重入锁定并且共享资源被锁定,则等待时间最长的线程(在这种情况下为P1)将首先获得锁定,然后是P2,然后是P3,然后是任何之后的其他线程。

如果您有一种方法可以为存储在队列中的元素分配值,这可以用于它们的排序,而不是使用PriorityBlockingQueue而不是SynchronizedQueue 。 优先级队列的元素根据其自然顺序排序,或者由队列构建时提供的比较器排序。

例如,您可以将生成器的id存储在元素中,并让Comparator知道如何比较生成器ID。

问题在于获取锁的顺序可以与产生元素的顺序任意不同,这甚至可以与生产者在multithreading环境中排队获取锁的顺序任意不同。 所以你最终遇到了你试图解决的同样问题。 (见递归 )

并非所有问题都可以通过另一层间接解决;-)

当然有可能:)通常这类问题通过在序列已知的位置添加序列号来解决。 在您的情况下,您的生产商可以生产序列号为“P1-1”,“P1-2”,“P2-1”等的产品,然后可以在一些处理后用于恢复订单。

这比维护顺序更可取,因为这种方式不可能进行某些优化(例如,搜索“Java重新排序”)。

你可以这样做:

 PriorityQueue priorityQueue = // give suitable comparator int seq = 0; void synchronized add(E e){ priorityQueue.add(e); } E synchronized poll(){ E candidate = priorityQueue.peek(); if(candidate.getSeq() == seq){ seq++; return priorityQueue.poll(); }else{ log.debug("{} hasn't arrived yet", seq); return null; } } 

这是一个错误的目标。 我认为你的生产者是线程。 线程执行顺序没有严格定义 – 一次线程A可以比线程B运行得更快,另一个时间B运行得更快,所以你想保留的顺序本身是随机的,不值得关注。 此外,将一个元素添加到队列的时间非常少,即使两个或多个线程同时执行它,您也可以将其视为在同一时刻发生的事情。

multithreading类似于相对论物理学 – 没有普遍的时间,只有在关系之前发生。 如果产生的事件之间存在这种关系,那么应该使用这种关系。 元素添加到公共队列的时间不能用作这种关系。