Is this code good implementation of using synchronized mechanism using semaphore in Java, I'm not sure if the length variable is safe because we have 2 methods there, I think that this is the right way, but I need someone to confirm this for me.
Thank you very much for your time!
public class BlockingQueue<T> {
static int length;
T[] contents;
int capacity;
public BlockingQueue(int capacity) {
contents = (T[]) new Object[capacity];
this.capacity = capacity;
}
public synchronized void enqueue(T item) throws InterruptedException {
while(length == this.capacity) {
wait();
}
contents[length++]= item;
if(contents.length == 1) {
notifyAll();
}
}
public synchronized T dequeue() throws InterruptedException{
while(length == 0){
wait();
}
if(length == capacity){
notifyAll();
}
T it = contents[0];
for(int i=1;i<length;i++)
{
contents[i-1]=contents[i]; //shifting left
}
length--;
return it;
}
}
The implementation looks correct. The structure you have with length and capacity essentially implements a semaphore. A few items can be improved I believe:
if(contents.length == 1) {
notifyAll();
}
If there are multiple producers, this is correct. If there is only one producer, notify() should suffice.
Instead of shifting contents, consider allocating capacity+1 and use a circular queue.
Related
I have a Counter class that stores value as AtomicInteger. That class should be thread safe. I have method boolean consume(int number) that should decrement counter and return true if counter >= number, and should not change counter and return false if counter < number
class Counter {
AtomicInteger counter = new AtomicInteger(initialValue);
boolean consume(int number) {
counter.accumulateAndGet(number, (prev, next) -> {
if (number <= prev) {
return prev - number;
} else {
// not modify the previous number;
return prev;
}
});
return ???
}
}
And I don't know if the function applied or not. I found the following solution
boolean consume(int number) {
AtomicBoolean result = new AtomicBoolean(false);
counter.accumulateAndGet(number, (prev, next) -> {
if (number <= prev) {
result.set(true);
return prev - number;
// function applied
} else {
result.set(false);
// not modify the previous number;
return prev;
}
});
return result.get();
}
but javadoc of accumulateAndGet sais:
The function should be side-effect-free, since it may be re-applied
when attempted updates fail due to contention among threads.
So, my solution has side effects. Is it safe to use? If not, how can I get the same result?
From the description, it sounds as if you want something like:
class Counter {
private final int initialValue = 42; // make compile
/** Non-negative count. */
private final AtomicInteger counter = new AtomicInteger(initialValue);
public boolean consume(int number) {
for (;;) {
int old = counter.get();
int next = old-number;
if (next >= 0) {
if (counter.compareAndSet(old, next)) {
return true;
};
} else {
return false;
}
}
}
}
since it may be re-applied when attempted updates fail due to
contention among threads.
The code in the question is fine with regarding to being executed one or more times, but it doesn't help to use convenience methods if they're not convenient.
I implemented my custom BlockingQueue<T> and compared it with java.util.concurrent ArrayBlockingQueue.
Here is my implementation:
public class CustomBlockingQueue<T> implements BlockingQueue<T> {
private final T[] table;
private final int capacity;
private int head = 0;
private int tail = 0;
private volatile int size;
private final Lock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition();
private final Condition notFull = lock.newCondition();
#SuppressWarnings("unchecked")
public CustomBlockingQueue(final int capacity) {
this.capacity = capacity;
this.table = (T[]) new Object[this.capacity];
size = 0;
}
#Override
public void add(final T item) throws InterruptedException {
lock.lock();
try {
while (size >= table.length) {
notFull.await();
}
if (tail == table.length) {
tail = 0;
}
table[tail] = item;
size++;
tail++;
if (size == 1) {
notEmpty.signalAll();
}
} finally {
lock.unlock();
}
}
#Override
public T poll() throws InterruptedException {
lock.lock();
try {
while (size == 0) {
notEmpty.await();
}
if (head == table.length) {
head = 0;
}
final T result = table[head];
table[head] = null;
size--;
head++;
if (size == capacity - 1) {
notFull.signalAll();
}
return result;
} finally {
lock.unlock();
}
}
#Override
public int size() {
return size;
}
}
My implementation is based on the array.
I don't ask you to review the code but help me to clarify the difference between my one and Java's.
In my code I do notEmpty.signalAll() or notFull.signalAll() inside the if clause but java.util.concurrent one simply invokes signal() in each case?
What is the reason for notifying another thread each time even when there's no necessary in it?
If a thread is blocking until it can read from or add to the queue, the best place for it is in the waitset for the applicable condition. That way it isn't contending actively for the lock and isn't getting context-switched into.
If only one item gets added to the queue, we want to signal only one consumer. We don't want to signal more consumers than we have items in the queue, because it makes more work for the system to have to manage and give timeslices to all the threads that can't make progress regardless.
That's why ArrayBlockingQueue signals one at a time for each time an item is enqueued or dequeued, in order to avoid unnecessary wakeups. In your implementation everybody in the waitset gets woken up on the transition (from empty to non-empty, or from full to not full), regardless of how many of those threads will be able to get their work accomplished.
This gets more significant as more threads are hitting this concurrently. Imagine a system with 100 threads waiting to consume something from the queue, but only one item is added every 10 seconds. It would be better not to kick out 100 threads from the waitset just to have 99 of them have to go back in.
So, I am creating a generic data structure named "Sack". In this I add items to a sack, grab a random item, see if it's empty, or dump out its contents etc. Also I'm creating it to expand to hold as many items as needed.
Currently, I'm working on the add method and I'm having troubles on my add method, and I am trying to think of a way adding what's in my parameter into the sack.
import java.util.Arrays;
public class Sack<E>
{
public static final int DEFAULT_CAPACITY = 10;
private E [] elementData;
private int size;
#SuppressWarnings("unchecked")
public Sack()
{
elementData = (E[]) new Object[DEFAULT_CAPACITY];
}
#SuppressWarnings("unchecked")
public Sack(int capacity)
{
if(capacity < 0)
{
throw new IllegalArgumentException("capacity " + capacity);
}
this.elementData = (E[]) new Object[capacity];
}
public boolean isEmpty()
{
if(size == 0)
{
return true;
}
else
{
return false;
}
}
public E [] dump()
{
E [] E2 = Arrays.copyOf(elementData, size);
for(int i = 0; i < size; i++)
{
elementData[i] = null;
}
size = 0;
return E2;
}
In this method, I am trying to add item, into my sack. When I run my tests, I am told it's incorrect. If there's a way to improve this.
public void add(E item)
{
elementData[size] = item;
size++;
}
elementData is what I am adding the items into.
Update
I updated my add method to look like this.
public void add(E item)
{
if(size >= elementData.length-1)
{
elementData[size] = item;
size++;
}
}
The message I am now receiving is that add is not working correctly and to check size usage.
You cannot ensure capacity of Java arrays, Javascript can! You can create a new one and copy:
public void add(E element) {
int index = size++;
if(size >= elementData.length-1) {
// it ensures elementData
elementData = java.util.Arrays.copyOf(elementData, size);
}
elementData[index] = element;
}
or skip ensure of array capacity and change the check direction:
public void add(E element) {
if(size < elementData.length-1) {
elementData[size++] = element;
}
// TODO else notice of the unsuccessfull add
}
It sounds like there's a spec for what your Sack is supposed to do that you did not paste.
It also sounds like your add method is supposed to just work, even if the sack is already at capacity.
That means you need to make a new array, copy over all elements, and then replace the array you have in your Sack instance with the new one (because java arrays cannot grow or shrink).
Look at the source of of java's own ArrayList for a hint on how that's done.
So after numerous tries, I give credit to #rockfarkas for solving this. I put in the following code and it solved my add method code.
public void add(E item)
{
int index = size++;
if(size >= elementData.length-1)
{
elementData = Arrays.copyOf(elementData, size);
}
elementData[index] = item;
}
Here's another way of doing this,
public void add(E item)
{
ensureCapacity(size+1);
elementData[size] = item;
size++;
}
This also works, but I would have to modify the ensureCapacity method accurately, which I have.
Unlike ArrayList, there is no get(int index) method in Queue to retrieve the element at specified position.
Anybody please tell me how to achieve this in Queue?
Thanks.
Accessing elements by index is not part of the concept of a queue.
If you need to access elements by index, you want a list, not a queue.
You can remove elements from the Queue until you reach the needed one. You can re-add the removed elements at the end of the queue or put them in a different queue (and add the rest after you reached the needed element).
You really shouldn't be using a Queue like that, though!
public static <T> T get(Queue<T> queue, int index) {
synchronized (queue) {
if (queue == null) {
return null;
}
int size = queue.size();
if (index < 0 || size < index + 1) {
return null;
}
T element = null;
for (int i = 0; i < size; i++) {
if (i == index) {
element = queue.remove();
} else {
queue.add(queue.remove());
}
}
return element;
}
}
public static Object retrieveElement(int index, Queue q) {
Iterator it = q.iterator();
int count = 0;
while (it.hasNext()) {
Object e = it.next();
if (count == index) {
it.remove();
return e;
}
count++;
}
return null;
}
public static <T> T getFromQueue(Queue<T> queue, int index){
if(index>=queue.size()){
throw new IndexOutOfBoundsException("index="+index+",size="+queue.size());
}
Queue<T> queueCopy = new LinkedList<T>(queue);
for(int i=0; i<index; i++){
queueCopy.remove();
}
return queueCopy.peek();
}
Queues operate in a first in first out (FIFO) manner therefore in order to access a particular element the elements must be removed and stored in a secondary queue until the element being searched for is identified
private static List<Individual> queueToList(Queue<Individual> archive) {
List<Individual> list = new LinkedList<Individual>();
Iterator<Individual> it = archive.iterator();
while(it.hasNext()){
list.add(it.next());
}
return list;
}
Basically the concept of Queue is FIFO(First In First Out).So accessing the particular index or the element in the queue is not possible. The other way is to get a particular element you need to delete it unless and until you get it.
Does Java have an easy way to reevaluate a heap once the priority of an object in a PriorityQueue has changed? I can't find any sign of it in Javadoc, but there has to be a way to do it somehow, right? I'm currently removing the object then re-adding it but that's obviously slower than running update on the heap.
You might need to implement such a heap yourself. You need to have some handle to the position of the item in the heap, and some methods to push the item up or down when its priority has changed.
Some years ago I wrote such a heap as part of a school work. Pushing an item up or down is an O(log N) operation. I release the following code as public domain, so you may use it in any way you please. (You might want to improve this class so that instead of the abstract isGreaterOrEqual method the sort order would rely on Java's Comparator and Comparable interfaces, and also would make the class use generics.)
import java.util.*;
public abstract class Heap {
private List heap;
public Heap() {
heap = new ArrayList();
}
public void push(Object obj) {
heap.add(obj);
pushUp(heap.size()-1);
}
public Object pop() {
if (heap.size() > 0) {
swap(0, heap.size()-1);
Object result = heap.remove(heap.size()-1);
pushDown(0);
return result;
} else {
return null;
}
}
public Object getFirst() {
return heap.get(0);
}
public Object get(int index) {
return heap.get(index);
}
public int size() {
return heap.size();
}
protected abstract boolean isGreaterOrEqual(int first, int last);
protected int parent(int i) {
return (i - 1) / 2;
}
protected int left(int i) {
return 2 * i + 1;
}
protected int right(int i) {
return 2 * i + 2;
}
protected void swap(int i, int j) {
Object tmp = heap.get(i);
heap.set(i, heap.get(j));
heap.set(j, tmp);
}
public void pushDown(int i) {
int left = left(i);
int right = right(i);
int largest = i;
if (left < heap.size() && !isGreaterOrEqual(largest, left)) {
largest = left;
}
if (right < heap.size() && !isGreaterOrEqual(largest, right)) {
largest = right;
}
if (largest != i) {
swap(largest, i);
pushDown(largest);
}
}
public void pushUp(int i) {
while (i > 0 && !isGreaterOrEqual(parent(i), i)) {
swap(parent(i), i);
i = parent(i);
}
}
public String toString() {
StringBuffer s = new StringBuffer("Heap:\n");
int rowStart = 0;
int rowSize = 1;
for (int i = 0; i < heap.size(); i++) {
if (i == rowStart+rowSize) {
s.append('\n');
rowStart = i;
rowSize *= 2;
}
s.append(get(i));
s.append(" ");
}
return s.toString();
}
public static void main(String[] args){
Heap h = new Heap() {
protected boolean isGreaterOrEqual(int first, int last) {
return ((Integer)get(first)).intValue() >= ((Integer)get(last)).intValue();
}
};
for (int i = 0; i < 100; i++) {
h.push(new Integer((int)(100 * Math.random())));
}
System.out.println(h+"\n");
while (h.size() > 0) {
System.out.println(h.pop());
}
}
}
PriorityQueue has the heapify method which re-sorts the entire heap, the fixUp method, which promotes an element of higher priority up the heap, and the fixDown method, which pushes an element of lower priority down the heap. Unfortunately, all of these methods are private, so you can't use them.
I'd consider using the Observer pattern so that a contained element can tell the Queue that its priority has changed, and the Queue can then do something like fixUp or fixDown depending on if the priority increased or decreased respectively.
The standard interfaces don't provide an update capability. You have use a custom type that implements this.
And you're right; although the big-O complexity of algorithms that use a heap doesn't change when you remove and replace the top of the heap, their actual run time can nearly double. I'd like to see better built-in support for a peek() and update() style of heap usage.
That's right. PriorityQueue of Java does not offer a method to update priority and it seems that deletion is taking linear time since it does not store objects as keys, as Map does. It in fact accepts same object multiple times.
I also wanted to make PQ offering update operation. Here is the sample code using generics. Any class that is Comparable can be used with it.
class PriorityQueue<E extends Comparable<E>> {
List<E> heap = new ArrayList<E>();
Map<E, Integer> map = new HashMap<E, Integer>();
void insert(E e) {
heap.add(e);
map.put(e, heap.size() - 1);
bubbleUp(heap.size() - 1);
}
E deleteMax() {
if(heap.size() == 0)
return null;
E result = heap.remove(0);
map.remove(result);
heapify(0);
return result;
}
E getMin() {
if(heap.size() == 0)
return null;
return heap.get(0);
}
void update(E oldObject, E newObject) {
int index = map.get(oldObject);
heap.set(index, newObject);
bubbleUp(index);
}
private void bubbleUp(int cur) {
while(cur > 0 && heap.get(parent(cur)).compareTo(heap.get(cur)) < 0) {
swap(cur, parent(cur));
cur = parent(cur);
}
}
private void swap(int i, int j) {
map.put(heap.get(i), map.get(heap.get(j)));
map.put(heap.get(j), map.get(heap.get(i)));
E temp = heap.get(i);
heap.set(i, heap.get(j));
heap.set(j, temp);
}
private void heapify(int index) {
if(left(index) >= heap.size())
return;
int bigIndex = index;
if(heap.get(bigIndex).compareTo(heap.get(left(index))) < 0)
bigIndex = left(index);
if(right(index) < heap.size() && heap.get(bigIndex).compareTo(heap.get(right(index))) < 0)
bigIndex = right(index);
if(bigIndex != index) {
swap(bigIndex, index);
heapify(bigIndex);
}
}
private int parent(int i) {
return (i - 1) / 2;
}
private int left(int i) {
return 2*i + 1;
}
private int right(int i) {
return 2*i + 2;
}
}
Here while updating, I am only increasing the priority (for my implementation) and it is using MaxHeap, so I am doing bubbleUp. One may need to heapify based on requirement.
Depending on the implementation of the data structure, there may not be a faster way. Most PQ/heap algorithms do not provide an update function. The Java implementation may not be any different. Notice that though a remove/insert makes the code slower, it is unlikely to result in code with a different runtime complexity.
Edit: have a look at this thread: A priority queue which allows efficient priority update?
Unfortunately, JDK's Priority Queue doesn't provide updates.
Robert Sedgewick and Kevin Wayne are well known for their algorithms courses in Princeton, and they also wrote Algorithms.
Inside this excellent book, they provide their own implementations for data structures, including updateable priority queues, such as IndexMinPQ.java
Licensed under GPLv3.
You need to implement it yourself. But you don't have to get fancy. The actual massive timesuck of removing the heap item in Java's implementation of remove(Object) is actually indexOf() since it has to iterate the entire list to find the index of the particular object. If you implement your own datastructure you can tell each object the position in the array and even if your implementation isn't anything fancy it'll outperform Java's since each object would know where its located in the array.
Storing that information you can do just the classic remove and add the new item and you'll beat Java by a lot.
The update routine just calls heapify on the particular index. It saves a heapify call, and some constant operations. The bulk of the optimization here is that Java's actual PriorityQueue can't store the index. So remove(Object) is actually a pretty expensive operation within that datastructure. As you're going to have to locate that Object in the list. This particular class reduces the time taken by PriorityQueue to nearly nothing. Though it requires that you implement Heap.Indexed on the items you put in the heap.
import java.util.Arrays;
public class Heap<T extends Heap.Indexed<T>> {
private Indexed[] heap;
private int length = 0;
public Heap() {
heap = new Indexed[12];
}
private void ensureCapacity() {
if (length > heap.length) {
heap = Arrays.copyOf(heap, length * 2);
}
}
public void add(T obj) {
int index = length++;
ensureCapacity();
obj.setIndex(index);
heap[index] = obj;
heapify(index);
}
public T removeAt(int index) {
T result = get(index);
length -= 1;
if ((length > 0) && (index != length)) {
swap(index, length);
heapify(index);
}
result.setIndex(-1);
heap[length] = null;
return result;
}
public T remove(T obj) {
int index = obj.getIndex();
if (index == -1) {
return null;
}
return removeAt(index);
}
public void update(T obj) {
int index = obj.getIndex();
obj.setIndex(-1);
if (index == -1) {
return;
}
heapify(index);
}
public T poll() {
if (length == 0) {
return null;
}
return removeAt(0);
}
public T peek() {
return get(0);
}
public T get(int index) {
return (T) heap[index];
}
public int size() {
return length;
}
protected boolean compare(int first, int last) {
return get(first).compareTo(get(last)) > -1;
}
protected void swap(int i, int j) {
T tmp = (T) heap[i];
heap[i] = (T) heap[j];
heap[j] = tmp;
heap[i].setIndex(i);
heap[j].setIndex(j);
}
public void heapify(int index) {
int parent = (index - 1) / 2;
if (index > 0 && !compare(parent, index)) {
swap(parent, index);
heapify(parent);
return;
}
int left = (index << 1) + 1;
int right = left + 1;
int largest = index;
if (left < length && !compare(largest, left)) {
largest = left;
}
if (right < length && !compare(largest, right)) {
largest = right;
}
if (largest != index) {
swap(largest, index);
heapify(largest);
}
}
public boolean isEmpty() {
return length == 0;
}
public void clear() {
this.length = 0;
Arrays.fill(heap, null);
}
public interface Indexed<I extends Heap.Indexed> extends Comparable<I> {
int getIndex();
void setIndex(int index);
}
}