在最近的一次采访中,我被要求实现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的多线程部分。
答案 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;
}