/**
* Copyright 2013, Landz and its contributors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package z.channel.contrast;
import org.junit.Test;
import z.testware.common.Stopwatch;
import java.util.LinkedList;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.stream.IntStream;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static z.util.Throwables.uncheck;
/**
*
[Stopwatch(Stopped): offer 50,000,000 times to an ArrayBlockingQueue
]{elapsed 1681 milliseconds}
[Stopwatch(Stopped): offer 50,000,000 times to a LinkedBlockingQueue
]{elapsed 51266 milliseconds}
[Stopwatch(Stopped): offer 50,000,000 times to a LinkedTransferQueue
]{elapsed 41966 milliseconds}
[Stopwatch(Stopped): offer 50,000,000 times to a NavieBlockingQueue
]{elapsed 26193 milliseconds}
[Stopwatch(Stopped): offer 50,000,000 times to a ConcurrentLinkedQueue
]{elapsed 13799 milliseconds}
*
* the main tested point here is the first step of offering objects.
* It is so slow for queue. The most problem here is that the unbound queue
* needs to new node object.
*
*/
public class BasicsOfJUCQueue {
private static final int RUNS = 50_000_000;
public static final Object OBJECT = new Object();
@Test
public void testOfferOfCLQ() {
ConcurrentLinkedQueue<Object> clq = new ConcurrentLinkedQueue();
Stopwatch watch = Stopwatch.create(String.format("offer %,d times to a ConcurrentLinkedQueue\n", RUNS));
watch.start();
IntStream.range(0,RUNS).forEach((i)->
clq.offer(OBJECT)
);
watch.stop();
watch.printMillis();
assertThat(clq.size(), is(RUNS));
}
@Test
public void testPutOfABQ() {
ArrayBlockingQueue<Object> abq = new ArrayBlockingQueue(RUNS);
Stopwatch watch = Stopwatch.create(String.format("offer %,d times to an ArrayBlockingQueue\n", RUNS));
watch.start();
IntStream.range(0,RUNS).forEach((i)->
uncheck(() -> abq.put(OBJECT))
);
watch.stop();
watch.printMillis();
assertThat(abq.size(), is(RUNS));
}
@Test
public void testPutOfLTQ() {
LinkedTransferQueue<Object> ltq = new LinkedTransferQueue();
Stopwatch watch = Stopwatch.create(String.format("offer %,d times to a LinkedTransferQueue\n", RUNS));
watch.start();
IntStream.range(0,RUNS).forEach((i) ->
ltq.put(OBJECT)
);
watch.stop();
watch.printMillis();
assertThat(ltq.size(), is(RUNS));
}
@Test
public void testPutOfLBQ() {
LinkedBlockingQueue<Object> lbq = new LinkedBlockingQueue();
Stopwatch watch = Stopwatch.create(String.format("offer %,d times to a LinkedBlockingQueue\n", RUNS));
watch.start();
IntStream.range(0,RUNS).forEach((i) ->
uncheck(() -> lbq.put(OBJECT))
);
watch.stop();
watch.printMillis();
assertThat(lbq.size(), is(RUNS));
}
@Test
public void testPutOfNVQ() {
NavieBlockingQueue<Object> nbq = new NavieBlockingQueue(RUNS);
Stopwatch watch = Stopwatch.create(String.format("offer %,d times to a NavieBlockingQueue\n", RUNS));
watch.start();
IntStream.range(0,RUNS).forEach((i) ->
uncheck(() -> nbq.put(OBJECT))
);
watch.stop();
watch.printMillis();
assertThat(nbq.size(), is(RUNS));
}
static class NavieBlockingQueue<T> {
private LinkedList<T> queue = new LinkedList<>();
private int limit = 16;
public NavieBlockingQueue(int limit){
this.limit = limit;
}
public synchronized void put(T item)
throws InterruptedException {
while(this.queue.size() == this.limit) {
wait();
}
if(this.queue.size() == 0) {
notifyAll();
}
this.queue.add(item);
}
public synchronized T take()
throws InterruptedException{
while(this.queue.size() == 0){
wait();
}
if(this.queue.size() == this.limit){
notifyAll();
}
return this.queue.remove(0);
}
//XXX: NotThreadSafe
public int size() {
return queue.size();
}
}
}