实现一个只能访问n个线程的队列 - 休息应该排队

时间:2015-03-03 06:07:01

标签: java multithreading

在最近的一次采访中,我被要求实现Queue,允许一次只访问四个线程。请求访问的任何其他线程应该排队,并且应该按照它们排队的顺序对它们进行优先级访问。我提出了以下Queue实现,但是无法想出代码的多线程部分。

public class Queue<Item> implements Iterable<Item> {
    private int N;               // number of elements on queue
    private Node<Item> first;    // beginning of queue
    private Node<Item> last;     // end of queue

    private static class Node<Item> {
        private Item item;
        private Node<Item> next;
    }

    public Queue() {
        first = null;
        last  = null;
        N = 0;
    }

    public boolean isEmpty() {
        return first == null;
    }

    public int size() {
        return N;     
    }

    public Item peek() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        return first.item;
    }

    public void enqueue(Item item) {
        Node<Item> oldlast = last;
        last = new Node<Item>();
        last.item = item;
        last.next = null;
        if (isEmpty()) first = last;
        else           oldlast.next = last;
        N++;
    }

    public Item dequeue() {
        if (isEmpty()) throw new NoSuchElementException("Queue underflow");
        Item item = first.item;
        first = first.next;
        N--;
        if (isEmpty()) last = null;
        return item;
    } 
}

您如何保证一次只能访问队列中的n个线程?

另外,请建议一些好的读取,这些读取有这些问题,以便我可以处理Java的多线程部分。

2 个答案:

答案 0 :(得分:2)

使用信号量。您可以使用number(permit)n初始化Semaphore并获取以访问队列。如果所有许可都被占用,获取将阻止。

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html

信号量限制获取资源的线程数。已经拥有资源的线程可以再次获取它。因此,信号量在内部维护线程标识。

在您的方案中,每个队列方法都应获取许可,并在方法结束时释放它。

即使两个流氓线程在其中传递队列对象,信号量也会通过跟踪线程标识来帮助维护许可。

答案 1 :(得分:0)

由线程调用意味着您通过Thread.currentThread()引用了该线程。您永远不能阻止线程调用您,但是您可以通过将此调用返回的不同Thread对象的数量限制为4来阻止使用队列对象的线程,当然您也可以我需要一种线程安全的方法来检查它。

以这种方式:

private Set<Thread> threads = new HashSet<>();

private synchronized void checkOk() {
    if (threads.size() < 4) {
        threads.add(Thread.currentThread());
    } else {
        if (!threads.contains(Thread.currentThread()))
            throw new IllegalStateException();
    }
}

然后将方法调用添加到每个公共方法,如下所示:

public Item peek() {
    checkOk();
    if (isEmpty()) throw new NoSuchElementException("Queue underflow");
    return first.item;
}