3

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

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

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

4

6 回答 6

1

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

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

现在,您可以使用 aPriorityBlockingQueue代替您的SynchronizedQueue,并在类中实现Comparator接口。PriorityP

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

于 2013-09-12T06:35:52.353 回答
0

当然有可能 :) 通常这类问题是通过在已知序列的地方添加序列号来解决的。在您的情况下,您的生产者可以生产具有“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;
    }
}
于 2013-09-12T06:46:37.010 回答
0

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

并非所有问题都可以通过另一个级别的间接来解决;-)

于 2013-09-12T06:56:11.927 回答
0

这是一个错误的目标。我假设您的生产者是线程。线程执行顺序没有严格定义——一次线程 A 可以比线程 B 运行得更快,另一次 B 运行得更快,因此您要保留的顺序本身就是随机的,不值得关心。此外,将元素添加到队列所花费的时间是如此之少,以至于即使是两个或多个线程同时执行,您也可以将其视为发生在同一时刻。

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

于 2013-09-12T07:43:22.663 回答
0

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

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

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

于 2013-09-12T06:27:52.993 回答
0

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

例如,您可以将生产者的 id 存储在元素中,并拥有一个知道如何比较生产者 id的Comparator 。

于 2013-09-12T06:34:45.103 回答