ConcurrentLinkQueue implementation going into deadlock - java

I am learning concurrent programming and wrote this concurrentLinkeQueue using AtomicReference.
Following Example goes into Deadlock. Please see.
package concurrent.AtomicE;
import java.util.concurrent.atomic.AtomicReference;
public class ConcurrentLinkQueue<V> {
private AtomicReference<Node> head = new AtomicReference<Node>();
public void offer(final V data) {
final Node<V> newNode = new Node<V>(data,Thread.currentThread().getName());
System.out.println("*********** NEW "+ newNode);
AtomicReference<Node> pointer = head;
for(;;){
if(pointer.get() == null){ // Threads wait here for infinite time
final boolean success = pointer.compareAndSet(null,newNode);
System.out.println(Thread.currentThread().getName() +" " + success);
if(success)
{
System.out.println(Thread.currentThread().getName() +"Returning");
return;
}else{
final Node<V> current = pointer.get();
pointer = current.next;
System.out.println(Thread.currentThread().getName() +" Next Pointer");
}
}
}
}
public void printQueueData(){
AtomicReference<Node> pointer = head;
for(;pointer!=null;){
final Node node = pointer.get();
System.out.println(node);
pointer = node.next;
}
}
private static class Node<V>{
private AtomicReference<Node> next;
private volatile V data = null;
private String threadName = "";
Node(V data1,String threadName){
this.data = data1;
this.threadName = threadName;
}
#Override
public String toString() {
return "threadName=" + threadName +
", data=" + data;
}
private AtomicReference<Node> getNext() {
return next;
}
private void setNext(AtomicReference<Node> next) {
this.next = next;
}
private V getData() {
return data;
}
private void setData(V data) {
this.data = data;
}
}
}
package concurrent.AtomicE;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public class Main {
private static final ConcurrentLinkQueue<Integer> clq = new ConcurrentLinkQueue<Integer>();
public static void main(String[] args) throws InterruptedException {
Task t = new Task();
Thread t1 = new Thread(t); t1.setName("t1");
Thread t2 = new Thread(t); t2.setName("t2");
//Thread t3 = new Thread(t); t3.setName("t3");
//Thread t4 = new Thread(t); t4.setName("t4");
//Thread t5 = new Thread(t); t5.setName("t5");
t1.start();
t2.start();
//t3.start();
//t4.start();
//t5.start();
t1.join();
t2.join();
//t3.join();
//t4.join();
//t5.join();
}
private static class Task implements Runnable{
#Override
public void run() {
for(int i=0;i<5;++i){
clq.offer(i);
}
}
}
}
after taking thread dump it shows that threads wait forever at following line
if(pointer.get() == null){ // Threads wait here for infinite time
can you please help why threads wait here forever?
[EDIT]
Solved it --->
public class ConcurrentLinkQueue<V> {
private final AtomicReference<Node> firstNodePointer = new AtomicReference<Node>();
public void offer(final V data) {
final Node<V> newNode = new Node<V>(data,Thread.currentThread().getName());
System.out.println(newNode);
final Node<Integer> firstNode = firstNodePointer.get();
if(firstNode == null){
if(firstNodePointer.compareAndSet(null,newNode) == true)
return;
}
boolean success = false;
Node<Integer> nodePointer = firstNode;
AtomicReference<Node> atomicRefPointer = firstNodePointer;
while(!success){
atomicRefPointer = nodePointer.getNext();
if(atomicRefPointer.get() == null){
success = atomicRefPointer.compareAndSet(null,newNode);
}else{
nodePointer = atomicRefPointer.get();
}
}
}
}
Another Solution->
public void fastOffer(final V data){
final Node<V> newNode = new Node<V>(data,Thread.currentThread().getName());
System.out.println(newNode);
AtomicReference<Node> pointer = firstNodePointer;
for(;;){
if(pointer.compareAndSet(null,newNode)){
return;
}
pointer = pointer.get().getNext();
}
}

In your example condition pointer.get() == null always returns false excepts first case when you assign it to head, because in Node class it null. You can assign it with default value and remove null check.
I suggest you to change a bit Node class, make it immutable:
private static class Node<V> {
private final AtomicReference<Node> next = new AtomicReference<>();
private final V data;
private final String threadName;
Node(V data1, String threadName) {
this.data = data1;
this.threadName = threadName;
}
}
And then you can simple go through all elements:
private final AtomicReference<Node> head = new AtomicReference<>();
#SuppressWarnings("unchecked")
public void offer(final V data) {
// create new Node
final Node<V> newNode = new Node<>(data, Thread.currentThread().getName());
// set root element if it's null
if (head.compareAndSet(null, newNode)) {
return;
}
// else pass trough all elements and try to set new
Node<V> pointer = head.get();
for (;;) {
if (pointer.next.compareAndSet(null, newNode)) {
break;
}
pointer = pointer.next.get();
}
}
And change print method:
#SuppressWarnings("unchecked")
public void printQueueData() {
AtomicReference<Node> pointer = head;
while (pointer.get() != null) {
System.out.println(pointer.get().data);
pointer = pointer.get().next;
}
}

Related

java.lang.NullPointerException while filling a generic list

So, im programming with Bluej in school, and our aim was to use a generic list to graphically design a
Pokedex. Im having no problems designing the interface, but when filling the list, i have a problem.
--The List(self-made,so im providing it whole,but focused on some stuff the teacher told us needed to be in there)--
import basis.*;
public class List<ContentType>
{
private Node<ContentType> head;
private Node<ContentType> tail;
private Node<ContentType> current;
private int Listlenght;
private boolean isEmpty;
private boolean hasAccess;
public List(){
head = null;
tail = null;
current = null;
}
public int Listlenght(){
int counter= 0;
toFirst();
while(hasAccess()){
next();
counter++;
}
return counter;
}
public boolean isEmpty(){
return head== null;
}
public boolean hasAccess(){
return current!=null;
}
public void next(){
if(isEmpty())
System.out.println("Liste ist leer");
else{
if(!hasAccess())
System.out.println("Kein momentanes Current");
else{
current= current.getNachfolger();
}
}
}
public void toFirst(){
if(isEmpty())
System.out.println("Liste ist leer");
else
current=head;
}
public void toLast(){
if(isEmpty())
System.out.println("Liste ist leer");
else
current=tail;
}
public Node<ContentType> getCurrent(){
if(hasAccess)
return current;
else{
System.out.println("Kein momentanes Current");
return null;
}
}
public void setCurrent(Node<ContentType> pCurrent){
if(hasAccess){
if(pCurrent!= null)
current.setInhalt(pCurrent.getInhalt());
}
else
System.out.println("Kein momentanes Current");
}
public void append(ContentType pContent){
if(pContent != null){
Node<ContentType> N;
N =new Node<ContentType>();
N.setNachfolger(null);
N.setInhalt(pContent);
if(isEmpty){
head =N;
}
else
tail.setNachfolger(N);
tail = N;
}
}
public void insert(ContentType pContent){
if(pContent != null){
if(hasAccess()){
Node<ContentType> N;
N =new Node<ContentType>();
N.setInhalt(pContent);
N.setNachfolger(current);
getPrevious(current).setNachfolger(N);
}
else
System.out.println("Kein momentanes Current");
if(isEmpty())
append(pContent);
}
else{
System.out.println("Kein Inhalt");
}
}
public void concat(List<ContentType> pList){
if (pList != this && pList != null && !pList.isEmpty()) {
pList.toFirst();
int i;
for(i=0;i< pList.Listlenght();i++){
//append(pList.getCurrent().getInhalt());
pList.next();
}
}
}
public void remove(){
if(hasAccess ){
getPrevious(current).setNachfolger(current.getNachfolger());
next();
}
}
private Node<ContentType> getPrevious(Node<ContentType> pNode) {
if (pNode != null && pNode != head && !this.isEmpty()) {
Node<ContentType> temp = head;
while (temp != null && temp.getNachfolger() != pNode) {
temp = temp.getNachfolger();
}
return temp;
} else {
return null;
}
}
}
import basis.*;
public class Node <ContentTypeN> {
private ContentTypeN inhalt;
private Node<ContentTypeN> Nachfolger;
public Node(){
Nachfolger = null;
}
public void setInhalt(ContentTypeN ninhalt){
this.inhalt= ninhalt;
}
public void setNachfolger(Node nNachfolger){
this.Nachfolger= nNachfolger;
}
public ContentTypeN getInhalt(){
return inhalt;
}
public Node<ContentTypeN> getNachfolger(){
return Nachfolger;
}
}
-- My Object Class --
import basis.*;
public class Pokemon{
private int Index;
private String Name;
private String Typ;
public Pokemon(int pIndex,String pName, String pTyp){
Index = pIndex;
Name = pName;
Typ = pTyp;
}
public int Index(int X){
return X;
}
}
The main class
import basis.*;
public class Anwendung
{
private Fenster Window;
private Farbe Color;
private Maus mouse;
private List<Pokemon> Pokedex;
private TextFeld TFStatus;
private TextFeld TFName;
private TextFeld TFTyp;
private ZahlenFeld ZFNummer;
private Knopf Knext;
private Knopf KtoFirst;
private Knopf ktoLast;
public Anwendung(){
WindowDesign();
gottacatchthemall();
IhaveNoIdea();
}
public void IhaveNoIdea(){
Pokedex.toFirst();
Pokedex.getCurrent().getInhalt();
}
public void WindowDesign(){
Window= new Fenster(700,700);
//Window.setzeHintergrundFarbe(Color.GRUEN);
Window.setzeTitel("Pokedex");
Pokedex = new List<Pokemon>();
mouse = new Maus();
TFZFGeneration();
KnopfGeneration();
}
public void KnopfGeneration(){
Knext = new Knopf();
Knext.setzePosition(550, 300);
Knext.setzeText("next");
KtoFirst = new Knopf();
KtoFirst.setzePosition(550, 350);
KtoFirst.setzeText("toFirst");
ktoLast = new Knopf();
ktoLast.setzePosition(550, 400);
ktoLast.setzeText("toLast");
}
public void TFZFGeneration(){
TFStatus = new TextFeld();
TFStatus.setzeGroesse(120,20);
TFStatus.setzePosition(0,0);
TFStatus.setzeEditierbar(false);
TFStatus.setzeText("Methode");
TFName = new TextFeld();
TFName.setzeGroesse(120,20);
TFName.setzePosition(400,300);
TFName.setzeEditierbar(false);
TFName.setzeText("PokeName");
TFTyp = new TextFeld();
TFTyp.setzeGroesse(120,20);
TFTyp.setzePosition(400,350);
TFTyp.setzeEditierbar(false);
TFTyp.setzeText("PokeTyp");
}
public void gottacatchthemall(){
TFStatus.setzeText("gottacatchthemall");
Pokemon P;
P = new Pokemon(1,"Bisasam","Pflanze");
Pokedex.append(P);
P = new Pokemon(2,"Bisaknosp","Pflanze");
Pokedex.append(P);
P = new Pokemon(3,"Bisaflor","Pflanze");
Pokedex.append(P);
P = new Pokemon(4,"Glumanda","Pflanze");
Pokedex.append(P);
P = new Pokemon(5,"Glutexo","Feuer");
Pokedex.append(P);
P = new Pokemon(6,"Glurak","Feuer");
Pokedex.append(P);
P = new Pokemon(7,"Schiggy","Wasser");
Pokedex.append(P);
P = new Pokemon(8,"Schillok","Wasser");
Pokedex.append(P);
P = new Pokemon(9,"Turtok","Wasser");
Pokedex.append(P);
}
}
Now the Problem: Whenever i start the class "Anwendung"a error Occurs. it says:
java.lang.NullPointerException
at List.append(List.java:100)
at Anwendung.gottacatchthemall(Anwendung.java:88)
at Anwendung.<init>(Anwendung.java:25)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at bluej.runtime.ExecServer$3.lambda$run$1(ExecServer.java:834)
at bluej.runtime.ExecServer.runOnTargetThread(ExecServer.java:930)
at bluej.runtime.ExecServer$3.run(ExecServer.java:832)
Apparently there is a problem with this line
}
else
tail.setNachfolger(N);
It seems that the tail is undefined,even though it gets defined a few lines down and this line isnt active since there is a if condition that blocks the else condition from going off when the list is empty. the list is empty at the start,i checked that.
When i remove this code it seems the list doesnt get filled at all,since the methode goFirst doesnt work at all.
The Interface
Any suggestions?
Im kinda stuck and my teacher couldnt explain it to me either, so im sorry if im a bit unspecific.
You said that "It seems that the tail is undefined,even though it gets defined a few lines down" - what do you mean by that? In Java you must first assign value - "few lines above".
if(isEmpty){
head =N;
}
else
tail.setNachfolger(N); // Use brackets
tail = N;
In the code above it seems that your are trying to call tail.setNachfolger(N) before initializing tail, so tail is null, therefore NullPointerException.
Also, please always do use brackets (near 'else'), because now it's not clear what was your intention.
It's hard to understand your code, but I think it should be:
else {
tail = N;
tail.setNachfolger(N);
}

NPE on LinkedList implementation, but I created the objects?

When main runs, the null pointer exception occurs at:
stringList.add("Test");
and specifically on this line of JAList in the add function:
dummy.getNextNode().setNodePrev(node);
I don't understand because at that point, dummy is initialized, dummy.getNextNode() is dummy, and node is initialized just before.
My only thought is that the constructor isn't setting the values properly when I call the constructor for JAList?
JAList<String> stringList = new JAList<String>();
As a side note, why don't you need the < E > when you create the constructor?
JANode.java:
public class JANode<E> {
private E value;
private JANode<E> next;
private JANode<E> prev;
public JANode(E value, JANode<E> next, JANode<E> prev)
{
this.value = value;
this.next = next;
this.prev = prev;
}
public E getValue()
{
return value;
}
public void setNodeNext(JANode<E> next)
{
this.next = next;
}
public JANode<E> getNextNode()
{
return next;
}
public JANode<E> getPrevNode()
{
return prev;
}
public void setNodePrev(JANode<E> prev)
{
this.prev = prev;
}
}
JAList.java:
public class JAList<E> {
private int initialCapacity;
private JANode<E> dummy;
public JAList()
{
this.initialCapacity= 10;
this.dummy = new JANode<E>(null, dummy, dummy);
}
public JAList(int initialCapacity)
{
this.initialCapacity = initialCapacity;
this.dummy = new JANode<E>(null, dummy, dummy);
}
public E add(E e)
{
JANode<E> node = new JANode<E>(e, dummy, dummy);
node.setNodeNext(dummy.getNextNode());
dummy.getNextNode().setNodePrev(node);
dummy.setNodeNext(node);
node.setNodePrev(dummy);
return e;
}
public JANode<E> getNode(E value)
{
JANode<E> local = dummy.getNextNode();
while (local != dummy && local.getValue() != value)
{
local = local.getNextNode();
}
return local;
}
}
main.java:
public class main {
public static void main(String[] args)
{
JAList<String> stringList = new JAList<String>();
stringList.add("Test");
stringList.add("B");
stringList.add("C");
System.out.println(stringList.getNode("Test").getValue());
System.out.println(stringList.getNode("Test").getNextNode().getValue());
}
}
Thank you.
Cause: At the moment of calling the constructor of JAList<E>, this line
this.dummy = new JANode<E>(null, dummy, dummy);
is the same that executing this:
this.dummy = new JANode<E>(null, null, null);
because you're using dummy as parameter but Java will initialize its value with null by default. Thus, when you later execute:
dummy.getNextNode().setNodePrev(node);
This part: dummy.getNextNode() returns null and it throws an NPE.
Solution: Change your code in the constructor to something like this:
this.dummy = null;
And in your add method, validate that is the current list is empty by evaluating if this.dummy is null:
public E add(E e) {
JANode<E> node = new JANode<E>(e, dummy, dummy);
if (dummy == null) {
dummy = node;
} else {
//your code for add goes here...
//note: it has errors as well...
//...
}
return e;
}

Multithreading with Singleton

I created a PrintQueue class which does printing related job. I made it singleton, as one network printer is shared by many users, so one instance should be created.
Here is my code:
abstract class Document {
protected String name;
protected String type;
Document(){}
Document(String name){
this.name = name;
}
public String name(){
return this.name;
}
abstract public String type();
}
class TextDocument extends Document {
TextDocument(String name){
super(name);
}
#Override
public String type() {
// TODO Auto-generated method stub
return "text";
}
}
class PdfDocument extends Document {
PdfDocument(String name){
super(name);
}
#Override
public String type() {
// TODO Auto-generated method stub
return "PDF";
}
}
class Node {
public Document document;
public Node next;
Node(Document d){
document = d;
}
}
class PrintQueue {
public Node root;
Node cur;
private static PrintQueue instance;
private PrintQueue(){}
public static synchronized PrintQueue getInstance(){
if(instance == null){
instance = new PrintQueue();
}
return instance;
}
public void push(Document d){
if(root == null){
root = new Node(d);
root.next =null;
}else{
cur = root;
while(cur.next!= null){
cur=cur.next;
}
Node newNode = new Node(d);
cur.next = newNode;
newNode.next = null;
}
}
public Document pop(){
if(root == null){
System.out.println("Queue is empty");
return null;
}else{
Node temp = root;
root=root.next;
System.out.println(temp.document.name()+" "+temp.document.type()+" popped out");
return temp.document;
}
}
public void displayContent(){
if(root == null){
System.out.println("no pending task");
}else{
cur = root;
while(cur!=null){
System.out.println(cur.document.name()+" "+cur.document.type());
cur = cur.next;
}
}
}
#Override
public void run() {
// TODO Auto-generated method stub
}
}
public class test {
public static void main(String[] args) {
Document a= new PdfDocument("loan agreement");
Document b= new TextDocument("Air Ticket");
Document c= new PdfDocument("movie ticket");
Document d= new TextDocument("bike riding");
PrintQueue p = PrintQueue.getInstance();
PrintQueue q = PrintQueue.getInstance();
p.push(a);
p.push(b);
q.push(c);
q.push(d);
p.displayContent();
System.out.println("-----------------------------------");
p.pop();
q.pop();
System.out.println("-----------------------------------");
p.displayContent();
}
}
I want to implement multithreading in my code where the push() method should be synchronized. Otherwise, if a document is sent by multiple users to the printer, it will not be saved in the print queue as expected.
I am new to multithreading, so I was thinking that I should extend Thread class to my printQueue, and in the run() method, I will call push(). However, I am unable to send a parameter to push() in that way and as my printQueue is singleton. I can't initialize document to be passed to push() in the constructor of printQueue.
How can I achieve this?
As far as I understand
you are dealing with consumer and producer problem, which is suitable to use BlockingQueue (example updated from doc) to keep the thread safety:
class DocProducer implements Runnable {
private final BlockingQueue queue;
Producer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... handle ...}
}
Document produce() { ... }
}
class DocConsumer implements Runnable {
private final BlockingQueue queue;
Consumer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... handle ...}
}
void consume(Document x) { ... }
}
class Setup {
void main() {
// or use your own thread-safe queue implementation,
// which is harder to be right, though
BlockingQueue printQueue = new LinkedBlockingQueue();
DocProducer p = new DocProducer(printQueue);
DocConsumer c1 = new DocConsumer(printQueue);
DocConsumer c2 = new DocConsumer(printQueue);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}
use runnalbe rather than extend thread, or better use ExecutorService
you want your consumer and producer to be multithreaded, which should have multi threads, but not your PrintQueue
Your problem is that you want to avoid calling push() method of your PrintQueue by multiple threads at the same time, then just make that method synchronized -
public synchronized void push(Document d){
if(root == null){
root = new Node(d);
root.next =null;
}else{
cur = root;
while(cur.next!= null){
cur=cur.next;
}
Node newNode = new Node(d);
cur.next = newNode;
newNode.next = null;
}
}
By making this method synchronized, you are ensuring that only one thread can enter inside this method at one time so will make this method thread-safe

Issue with creating Immutable Queue

I am using the following code to make an immutable queue.
import java.util.NoSuchElementException;
import java.util.Queue;
public class ImmutableQueue<E> {
//Two stacks are used. One is to add items to the queue(enqueue) and
//other is to remove them(dequeue)
private ImmutableQueue(ReversableStack<E> order, ReversableStack<E> reverse) {
this.order = order;
this.reverse = reverse;
}
//initially both stacks are empty
public ImmutableQueue() {
this.order = ReversableStack.emptyStack();
this.reverse = ReversableStack.emptyStack();
}
public ImmutableQueue<E> enqueue(E e) {
if (null == e)
throw new IllegalArgumentException();
return new ImmutableQueue<E>(this.order.push(e), this.reverse);
}
public ImmutableQueue<E> dequeue() {
if (this.isEmpty())
throw new NoSuchElementException();
if (!this.reverse.isEmpty()) {
return new ImmutableQueue<E>(this.order, this.reverse.tail);
} else {
return new ImmutableQueue<E>(ReversableStack.emptyStack(),
this.order.getReverseStack().tail);
}
}
private static class ReversableStack<E> {
private E head; //top of original stack
private ReversableStack<E> tail; //top of reversed stack
private int size;
//initializing stack parameters
private ReversableStack(E obj, ReversableStack<E> tail) {
this.head = obj;
this.tail = tail;
this.size = tail.size + 1;
}
//returns a new empty stack
public static ReversableStack emptyStack() {
return new ReversableStack();
}
private ReversableStack() {
this.head = null;
this.tail = null;
this.size = 0;
}
//Reverses the original stack
public ReversableStack<E> getReverseStack() {
ReversableStack<E> stack = new ReversableStack<E>();
ReversableStack<E> tail = this;
while (!tail.isEmpty()) {
stack = stack.push(tail.head);
tail = tail.tail;
}
return stack;
}
public boolean isEmpty() {
return this.size == 0;
}
public ReversableStack<E> push(E obj) {
return new ReversableStack<E>(obj, this);
}
}
private ReversableStack<E> order;
private ReversableStack<E> reverse;
private void normaliseQueue() {
this.reverse = this.order.getReverseStack();
this.order = ReversableStack.emptyStack();
}
public E peek() {
if (this.isEmpty())
throw new NoSuchElementException();
if (this.reverse.isEmpty())
normaliseQueue();
return this.reverse.head;
}
public boolean isEmpty() {
return size() == 0;
}
//returns the number of items currently in the queue
public int size() {
return this.order.size + this.reverse.size;
}
public static void main(String[] args)
{
ImmutableQueue<Integer> newQueue = new ImmutableQueue<Integer>();
newQueue.enqueue(5);
newQueue.enqueue(10);
newQueue.enqueue(15);
int x = newQueue.size();
//ImmutableQueue<Integer> x = newQueue.dequeue();
System.out.println(x);
}
}
But whenever I try to do a dequeue, I get a NoSuchElementException. Also, the newQueue.size function also returns 0.
What am I doing wrong ?
Thanks
You are missing the new ImmutableQueue reference..
since enqueue() method returns a new instance of ImmutableQueue
public ImmutableQueue<E> enqueue(E e) {
if (null == e)
throw new IllegalArgumentException();
return new ImmutableQueue<E>(this.order.push(e), this.reverse);
}
But on your main method you are discarding that object
public static void main(String[] args)
{
ImmutableQueue<Integer> newQueue = new ImmutableQueue<Integer>();
newQueue.enqueue(5);
newQueue.enqueue(10);
newQueue.enqueue(15);
int x = newQueue.size();
//ImmutableQueue<Integer> x = newQueue.dequeue();
System.out.println(x);
}
change your call to:
newQueue = newQueue.enqueue(5);
int x = newQueue.size();
System.out.println(x);
and you will see the size will change

how to terminate retrieval from a blocking queue

I have some code where i execute a several tasks using Executors and a Blocking Queue. The results have to be returned as an iterator because that is what the application that i work on expects. However, there is a 1:N relationship between the task and the results added to the queue, so i cannot use the ExecutorCompletionService. While calling hasNext(), i need to know when all the tasks have finished and added all the results to the queue, so that i can stop the retrieval of results from the queue. Note, that once items are put on the queue, another thread should be ready to consume (Executor.invokeAll(), blocks until all tasks have completed, which is not what i want, nor a timeout). This was my first attempt, i am using an AtomicInteger just to demonstrate the point even though it will not work. Could someone help me in undestanding how i can solve this issue?
public class ResultExecutor<T> implements Iterable<T> {
private BlockingQueue<T> queue;
private Executor executor;
private AtomicInteger count;
public ResultExecutor(Executor executor) {
this.queue = new LinkedBlockingQueue<T>();
this.executor = executor;
count = new AtomicInteger();
}
public void execute(ExecutorTask task) {
executor.execute(task);
}
public Iterator<T> iterator() {
return new MyIterator();
}
public class MyIterator implements Iterator<T> {
private T current;
public boolean hasNext() {
if (count.get() > 0 && current == null)
{
try {
current = queue.take();
count.decrementAndGet();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return current != null;
}
public T next() {
final T ret = current;
current = null;
return ret;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
public class ExecutorTask implements Runnable{
private String name;
public ExecutorTask(String name) {
this.name = name;
}
private int random(int n)
{
return (int) Math.round(n * Math.random());
}
#SuppressWarnings("unchecked")
public void run() {
try {
int random = random(500);
Thread.sleep(random);
queue.put((T) (name + ":" + random + ":1"));
queue.put((T) (name + ":" + random + ":2"));
queue.put((T) (name + ":" + random + ":3"));
queue.put((T) (name + ":" + random + ":4"));
queue.put((T) (name + ":" + random + ":5"));
count.addAndGet(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
And the calling code looks like:
Executor e = Executors.newFixedThreadPool(2);
ResultExecutor<Result> resultExecutor = new ResultExecutor<Result>(e);
resultExecutor.execute(resultExecutor.new ExecutorTask("A"));
resultExecutor.execute(resultExecutor.new ExecutorTask("B"));
Iterator<Result> iter = resultExecutor.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
Use "poison" objects in the Queue to signal that a task will provide no more results.
class Client
{
public static void main(String... argv)
throws Exception
{
BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
ExecutorService workers = Executors.newFixedThreadPool(2);
workers.execute(new ExecutorTask("A", queue));
workers.execute(new ExecutorTask("B", queue));
Iterator<String> results =
new QueueMarkersIterator<String>(queue, ExecutorTask.MARKER, 2);
while (results.hasNext())
System.out.println(results.next());
}
}
class QueueMarkersIterator<T>
implements Iterator<T>
{
private final BlockingQueue<? extends T> queue;
private final T marker;
private int count;
private T next;
QueueMarkersIterator(BlockingQueue<? extends T> queue, T marker, int count)
{
this.queue = queue;
this.marker = marker;
this.count = count;
this.next = marker;
}
public boolean hasNext()
{
if (next == marker)
next = nextImpl();
return (next != marker);
}
public T next()
{
if (next == marker)
next = nextImpl();
if (next == marker)
throw new NoSuchElementException();
T tmp = next;
next = marker;
return tmp;
}
/*
* Block until the status is known. Interrupting the current thread
* will cause iteration to cease prematurely, even if elements are
* subsequently queued.
*/
private T nextImpl()
{
while (count > 0) {
T o;
try {
o = queue.take();
}
catch (InterruptedException ex) {
count = 0;
Thread.currentThread().interrupt();
break;
}
if (o == marker) {
--count;
}
else {
return o;
}
}
return marker;
}
public void remove()
{
throw new UnsupportedOperationException();
}
}
class ExecutorTask
implements Runnable
{
static final String MARKER = new String();
private static final Random random = new Random();
private final String name;
private final BlockingQueue<String> results;
public ExecutorTask(String name, BlockingQueue<String> results)
{
this.name = name;
this.results = results;
}
public void run()
{
int random = ExecutorTask.random.nextInt(500);
try {
Thread.sleep(random);
}
catch (InterruptedException ignore) {
}
final int COUNT = 5;
for (int idx = 0; idx < COUNT; ++idx)
results.add(name + ':' + random + ':' + (idx + 1));
results.add(MARKER);
}
}
I believe a Future is what you're looking for. It allows you to associate asynchronous tasks with a result object, and query the status of that result. For each task you begin, keep a reference to its Future and use that to determine whether or not it has completed.
If I understand your problem correctly (which I'm not sure I do), you can prevent an infinite wait on an empty queue by using [BlockingQueue.poll][1] instead of take(). This lets you specify a timeout, after which time null will be returned if the queue is empty.
If you drop this straight into your hasNext implementation (with an appropriately short timeout), the logic will be correct. An empty queue will return false while a queue with
entities remaining will return true.
[1]: http://java.sun.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html#poll(long, java.util.concurrent.TimeUnit)
Here is an alternate solution that uses a non-blocking queue with wait/notify, AtomicInteger and a callback.
public class QueueExecutor implements CallbackInterface<String> {
public static final int NO_THREADS = 26;
private Object syncObject = new Object();
private AtomicInteger count;
Queue<String> queue = new LinkedList<String>();
public void execute() {
count = new AtomicInteger(NO_THREADS);
ExecutorService executor = Executors.newFixedThreadPool(NO_THREADS/2);
for(int i=0;i<NO_THREADS;i++)
executor.execute(new ExecutorTask<String>("" + (char) ('A'+i), queue, this));
Iterator<String> iter = new QueueIterator<String>(queue, count);
int count = 0;
while (iter.hasNext()) {
System.out.println(iter.next());
count++;
}
System.out.println("Handled " + count + " items");
}
public void callback(String result) {
System.out.println(result);
count.decrementAndGet();
synchronized (syncObject) {
syncObject.notify();
}
}
public class QueueIterator<T> implements Iterator<T> {
private Queue<T> queue;
private AtomicInteger count;
public QueueIterator(Queue<T> queue, AtomicInteger count) {
this.queue = queue;
this.count = count;
}
public boolean hasNext() {
while(true) {
synchronized (syncObject) {
if(queue.size() > 0)
return true;
if(count.get() == 0)
return false;
try {
syncObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public T next() {
synchronized (syncObject) {
if(hasNext())
return queue.remove();
else
return null;
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
class ExecutorTask<T> implements Runnable {
private String name;
private Queue<T> queue;
private CallbackInterface<T> callback;
public ExecutorTask(String name, Queue<T> queue,
CallbackInterface<T> callback) {
this.name = name;
this.queue = queue;
this.callback = callback;
}
#SuppressWarnings("unchecked")
public void run() {
try {
Thread.sleep(1000);
Random randomX = new Random();
for (int i = 0; i < 5; i++) {
synchronized (syncObject) {
Thread.sleep(randomX.nextInt(10)+1);
queue.add((T) (name + ":" + ":" + i));
syncObject.notify();
}
}
callback.callback((T) (name + ": Done"));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public interface CallbackInterface<T> {
void callback(T result);
}
And the calling code is simply:
QueueExecutor exec = new QueueExecutor();
exec.execute();
I am not sure I understand you, but why can't the worker threads put themselves Lists onto the Queue. You can then make a custom iterator that goes over the queue in an outer loop and through the subiterators. All without concurrency magic.

Categories

Resources