Why inner class method cannot synchronized the object in outer class? - java

I encountered a problem:Will inner class method cannot synchronized the object in outer class? A answer from stackoverflow told me : No. But I really want to know the reason.
For example:
I designed a thread pool with at most 5 threads to do work.
public class ThreadPool{
// Ignore the Task class
private LinkedList<Task> tasks;
Executor[] executors = new Executor[5];
private static ThreadPool pool = null;
private ThreadPool() {
tasks = new LinkedList<Task>();
for (int i = 0; i < 5; i++) {
executors[i] = new Executor(i);
}
}
public static ThreadPool getInstance() {
if (pool == null) {
pool = new ThreadPool();
}
return pool;
}
public void addTask(Task task) {
/** igore code here*/
}
private class Executor extends Thread {
private int i;
public Executor(int i) {
this.i = i;
start();
}
public void run() {
Task task = null;
synchronized (tasks) {
if (tasks.size() == 0) {
System.out.println("tasks's size is : " + tasks.size());
try {
while (tasks.size() == 0) {
tasks.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
if (tasks.size() > 0)
task = tasks.removeFirst();
}
if (task != null) {
/** ignore code here */
}
}
}
}
Unfortunately, the synchronized doesn't work. But when I put the synchronized block into
synchronized (ThreadPool.this) {
...
}
it works.
So, i want to know why inner class method cannot synchronized the object in outer class.
Hope for a detailed answer.

Related

Why just one of 5 threads pop elements from stack?

public class ClassTest extends Thread{
public static Object lock = new Object();
public static LinkedList<Integer> stack;
public SortedSet<Integer> set= new TreeSet<>();
#Override
public void run(){
synchronized(lock){
// try{
// this.wait();
// }
// catch(Exception e){
// e.printStackTrace();
// }
while(!stack.isEmpty()){
set.add(stack.pop());
this.yield();
// this.notifyAll();
}
}
}
When i start() 5 Threads why just first one pop all elements and others do not pop anyone?
I tried to use wait() and notify() methods, but that didn't help..
The method yield does not release locks. The very first thread that enters the synchronized block will keep other threads from entering until the stack is empty and the lock is released.
Here is an example that does what you want using LinkedBlockingDeque.
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.LinkedBlockingDeque;
class Main {
static final LinkedBlockingDeque<Integer> stack = new LinkedBlockingDeque<>();
static class Poller implements Runnable {
final Set<Integer> set = new HashSet<>();
#Override
public void run() {
Integer elem = stack.poll();
while (elem != null) {
set.add(elem);
System.out.printf("%s: %d\n", Thread.currentThread().getName(), elem);
elem = stack.poll();
}
}
}
public static void main(String args[]) {
for (int i = 0; i < 100; i++) {
stack.push(i);
}
for (int i = 0; i < 5; i++) {
new Thread(new Poller()).start();
}
}
}

Java Threads with ConcurrentModificationException

I'm currently working on my first multithreaded software - a program, which calculates prime numbers...
Basically I create n (number of Threads) runnables. These runnables are added to an ArrayList. They check, whether a number is a prime. If the number is a prime I add it into an long array for later use. Since I want the primes to be in correct order in this array I need specific Threads to wait for others. I do this by looping through the ArrayList (see above) and wait for the threads, which check a lower number.
After a thread is done I want to remove it from the given ArrayList, but I cant since the other threads are still looping through it (This is the reason why the ConcurrentModificationException occurs I guess - This is my first time working with threads...).
I honestly hope that any of you guys can help me :)
Thank your really much!
Matthias
My runnable class (I just create four objects of this class in the main method):
import java.util.ArrayList;
public class PrimeRunnable implements Runnable {
//Static Util
public static ArrayList<PrimeRunnable> runningThreads = new ArrayList<PrimeRunnable>();
public static long[] primes;
public static int nextFreeIndex = 1;
public static long nextPossiblePrime = 3;
//Object specific
private long numberToCheck;
private Thread primeThread;
private String threadName;
private long threadID;
public PrimeRunnable() {
numberToCheck = nextPossiblePrime;
increaseNextPossiblePrime();
threadName = "ThreadToCheck" + numberToCheck;
threadID = numberToCheck;
runningThreads.add(this);
}
#Override
public void run() {
boolean isPrime = true;
double sqrtOfPossiblePrime = Math.sqrt(numberToCheck);
long lastDevider = 0;
for(int index = 0; index < nextFreeIndex; index++) {
lastDevider = primes[index];
if(numberToCheck%primes[index] == 0) {
isPrime = false;
break;
}
if(primes[index] > sqrtOfPossiblePrime) {
break;
}
}
while(lastDevider < sqrtOfPossiblePrime) {
lastDevider += 1;
if(numberToCheck%lastDevider == 0) {
isPrime = false;
break;
}
}
if(isPrime) {
//Wait for lower Threads.
for(PrimeRunnable runnable : runningThreads) {
if(runnable.getThreadID() < this.getThreadID()) {
try {
runnable.primeThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
primes[nextFreeIndex] = numberToCheck;
increaseNextFreeIndex();
System.out.println(numberToCheck);
}
runningThreads.remove(this);
}
public void start() {
if(primeThread == null) {
primeThread = new Thread(this, threadName);
}
primeThread.start();
}
public void reset() {
numberToCheck = nextPossiblePrime;
increaseNextPossiblePrime();
threadName = "ThreadToCheck" + numberToCheck;
threadID = numberToCheck;
//No need to readd into runningThread, since we only manipulate an already existing object.
primeThread = new Thread(this, threadName);
primeThread.start();
}
public static void setUpperBorder(int upperBorder) {
if(primes == null) {
primes = new long[upperBorder];
primes[0] = 2;
} else {
System.err.println("You are not allowed to set the upper border while running.");
}
}
public long getNumberToCheck() {
return numberToCheck;
}
private void increaseNextPossiblePrime() {
nextPossiblePrime += 2;
}
private void increaseNextFreeIndex() {
nextFreeIndex += 2;
}
public long getThreadID() {
return threadID;
}
public boolean isAlive() {
return primeThread.isAlive();
}
}
I was able to replicate the issue and fix it using Java implementation of a concurrent list CopyOnWriteArrayList
Here's my main class
public class PrimeRunnableMain {
public static void main(String[] args) {
PrimeRunnable.setUpperBorder(10);
PrimeRunnable primeRunnable1 = new PrimeRunnable();
PrimeRunnable primeRunnable2 = new PrimeRunnable();
PrimeRunnable primeRunnable3 = new PrimeRunnable();
PrimeRunnable primeRunnable4 = new PrimeRunnable();
primeRunnable1.start();
primeRunnable2.start();
primeRunnable3.start();
primeRunnable4.start();
}
}
and here's PrimeRunnable
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class PrimeRunnable implements Runnable {
// Static Util
public static List<PrimeRunnable> runningThreads = new CopyOnWriteArrayList<PrimeRunnable>();
public static long[] primes;
public static int nextFreeIndex = 1;
public static long nextPossiblePrime = 3;
// Object specific
private long numberToCheck;
private Thread primeThread;
private String threadName;
private long threadID;
public PrimeRunnable() {
numberToCheck = nextPossiblePrime;
increaseNextPossiblePrime();
threadName = "ThreadToCheck" + numberToCheck;
threadID = numberToCheck;
runningThreads.add(this);
}
#Override
public void run() {
boolean isPrime = true;
double sqrtOfPossiblePrime = Math.sqrt(numberToCheck);
long lastDevider = 0;
for (int index = 0; index < nextFreeIndex; index++) {
lastDevider = primes[index];
if (numberToCheck % primes[index] == 0) {
isPrime = false;
break;
}
if (primes[index] > sqrtOfPossiblePrime) {
break;
}
}
while (lastDevider < sqrtOfPossiblePrime) {
lastDevider += 1;
if (numberToCheck % lastDevider == 0) {
isPrime = false;
break;
}
}
if (isPrime) {
// Wait for lower Threads.
for (PrimeRunnable runnable : runningThreads) {
if (runnable.getThreadID() < this.getThreadID()) {
try {
runnable.primeThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
primes[nextFreeIndex] = numberToCheck;
increaseNextFreeIndex();
System.out.println(numberToCheck);
}
runningThreads.remove(this);
}
public void start() {
if (primeThread == null) {
primeThread = new Thread(this, threadName);
}
primeThread.start();
}
public void reset() {
numberToCheck = nextPossiblePrime;
increaseNextPossiblePrime();
threadName = "ThreadToCheck" + numberToCheck;
threadID = numberToCheck;
// No need to readd into runningThread, since we only manipulate an
// already existing object.
primeThread = new Thread(this, threadName);
primeThread.start();
}
public static void setUpperBorder(int upperBorder) {
if (primes == null) {
primes = new long[upperBorder];
primes[0] = 2;
} else {
System.err
.println("You are not allowed to set the upper border while running.");
}
}
public long getNumberToCheck() {
return numberToCheck;
}
private void increaseNextPossiblePrime() {
nextPossiblePrime += 2;
}
private void increaseNextFreeIndex() {
nextFreeIndex += 2;
}
public long getThreadID() {
return threadID;
}
public boolean isAlive() {
return primeThread.isAlive();
}
}
What about a PrimeListener class that contains a synchronized method publishPrime that inserts the prime in the correct position in the list? Inserting at the right position into the list should not take too much time, if you start at the last index of a LinkedList.
Alternatively you could also insert it into a SortedSet (implementation: TreeSet). I presume you don't want any duplicate primes anyway. In that case synchronizedSortedSet may be directly used instead of the listener.
Note that you still seem rather stuck on lower level structures. When programming concurrently on Java it pays off to use the higher level constructs (executors, futures, concurrent queue's etc. etc.).
The main distinction between fail-fast and fail-safe iterators is
whether or not the collection can be modified while it is being
iterated. Fail-safe iterators allow this; fail-fast iterators do not.
Fail-fast iterators operate directly on the collection itself. During
iteration, fail-fast iterators fail as soon as they realize that the
collection has been modified (i.e., upon realizing that a member has
been added, modified, or removed) and will throw a
ConcurrentModificationException. Some examples include ArrayList,
HashSet, and HashMap (most JDK1.4 collections are implemented to be
fail-fast). Fail-safe iterates operate on a cloned copy of the
collection and therefore do not throw an exception if the collection
is modified during iteration. Examples would include iterators
returned by ConcurrentHashMap or CopyOnWriteArrayList.

Puzzle about two workers and a cart. Usage lock and conditions doesn't work

When using synchronized block or method, we synchronized by mutable object. But I don't understand how to use Locks with Conditions from j.u.c.. I'm trying to solve puzzle with two workers and a cart with lock and conditions. When first worker add weight to the cart - second wait. When cart is full, than first worker wait and second releases the cart.
I create two threads for each worker and use one cart. But in reality only one thread performs (worker, that add weight) until cart is full. Than program blocks. What I'm doing wrong and what I misunderstand?
That's my implementation of this puzzle.
package puzzles.workers;
public enum WorkerType {
ADDER, REDUCER;
}
Cart class
package puzzles.workers;
public class Cart {
private static final int INITIAL_CAPACITY = 10;
private static final int INITIAL_WEIGHT = 0;
private int capacity;
private int weight;
public Cart() {
this(INITIAL_CAPACITY);
}
public Cart(int capacity) {
this.capacity = capacity;
weight = INITIAL_WEIGHT;
}
public void addWeight() {
weight++;
}
public void reduceWeight() {
weight--;
}
public int getCapacity() {
return capacity;
}
public int getWeight() {
return weight;
}
}
Worker class.
package puzzles.workers;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class WorkerWithLock implements Runnable {
private final Cart cart;
private WorkerType workerType;
final Lock lock = new ReentrantLock();
final Condition whenEmpty = lock.newCondition();
final Condition whenFull = lock.newCondition();
public WorkerWithLock(Cart cart, WorkerType workerType) {
this.cart = cart;
this.workerType = workerType;
}
#Override
public void run() {
while (true) {
if (workerType == WorkerType.ADDER) {
try {
addWeight();
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
} else {
try {
reduceWeight();
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
}
public void addWeight() throws InterruptedException {
lock.lock();
try {
while (cart.getWeight() == (cart.getCapacity() - 1)) {
whenFull.await();
}
cart.addWeight();
System.out.println("++ weight is: " + cart.getWeight());
whenEmpty.signalAll();
Thread.sleep(500);
} finally {
lock.unlock();
}
}
public void reduceWeight() throws InterruptedException {
lock.lock();
try {
while (cart.getWeight() == 0) {
whenEmpty.await();
}
cart.reduceWeight();
System.out.println("-- weight is: " + cart.getWeight());
whenFull.signalAll();
Thread.sleep(500);
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
Cart cart = new Cart(5);
WorkerWithLock adder = new WorkerWithLock(cart, WorkerType.ADDER);
WorkerWithLock reducer = new WorkerWithLock(cart, WorkerType.REDUCER);
new Thread(reducer).start();
new Thread(adder).start();
}
}
It is a kind of a race condition
That is because both threads are waiting.
One in addWeightand one in reduceWeight.
First the reducer stops, if weight is 0. At this time, the adder is may be not already started.
Than the adder stops, if weight = cpacity - 1
Now, both are waiting for an interrupt().
EDIT1. See my comments in the code
public void addWeight() throws InterruptedException {
lock.lock();
try {
while (cart.getWeight() == (cart.getCapacity() - 1)) {
whenFull.await(); //<-- ADDER waits here
}
cart.addWeight();
System.out.println("++ weight is: " + cart.getWeight());
whenEmpty.signalAll(); //<-- Never called since both are waiting
Thread.sleep(500);
} finally {
lock.unlock();
}
}
public void reduceWeight() throws InterruptedException {
lock.lock();
try {
while (cart.getWeight() == 0) {
whenEmpty.await(); //<-- REDUCER waits here
}
cart.reduceWeight();
System.out.println("-- weight is: " + cart.getWeight());
whenFull.signalAll(); //<-- Never called since both are waiting
Thread.sleep(500);
} finally {
lock.unlock();
}
}
EDIT2: Ok, now I understand the behaviour.
Your code is designed to synchronize ONE object for multiple threads, but your are using TWO objects.
Every of your both WorkerWithLock Objects has its own Lock and Condition objects. So calls of lock.lock() and whenFull.signalAll() in object ADDER does not effect Object REDUCER.
Your code will work if you make the lock and condition variables static, so that both objects are working with the same lock and the same condition
final static Lock lock = new ReentrantLock();
final static Condition whenEmpty = lock.newCondition();
final static Condition whenFull = lock.newCondition();
Sometimes multithreading is hard :)

Java Multi threading

I have to use two threads such that one thread prints all the odd numbers less than 10, and the other to print even numbers less than 10 and the final output should be in sequence.
I have achieved this as follows. I want to do the same using synchronized methods? How to do it?
class printodd extends Thread{
public void run() {
super.run();
for(int i=0;i<10;i=i+2){
System.out.println("even "+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class printeven extends Thread{
public void run() {
super.run();
for(int i=1;i<10;i=i+2)
{
System.out.println("odd "+i);
try {
Thread.sleep(1050);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class PrintNumSeq{
public static void main(String[] args) {
printodd p=new printodd();
printeven e=new printeven();
e.start();
p.start();
}
}
Try this
public class PrintNumSeq extends Thread {
static Object lock = new Object();
static int n;
int even;
PrintNumSeq(int r) {
this.even = r;
}
public void run() {
try {
synchronized (lock) {
for (;;) {
while ((n & 1) != even) {
lock.wait();
}
n++;
lock.notify();
if (n > 10) {
break;
}
System.out.println(n);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new PrintNumSeq(1).start();
new PrintNumSeq(0).start();
}
}
output
1
2
3
4
5
6
7
8
9
10
public class SequentialThreadPrinter {
public static void main(String[] args) {
AtomicInteger counter = new AtomicInteger(0);
EvenThread even = new EvenThread("even", counter);
OddThread odd = new OddThread("odd", counter);
even.start();
odd.start();
}
}
private static class EvenThread extends Thread {
private String name;
private AtomicInteger counter;
public EvenThread(String name, AtomicInteger counter) {
this.name = name;
this.counter = counter;
}
public void run() {
do {
synchronized (counter) {
if (counter.get() % 2 == 0) {
System.out.println("Thread is " + name + ", Counter is = " + counter.getAndAdd(1));
counter.notifyAll();
} else {
try {
counter.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} while (counter.get() <= 10);
}
}
private static class OddThread extends Thread {
private String name;
private AtomicInteger counter;
public OddThread(String name, AtomicInteger counter) {
this.name = name;
this.counter = counter;
}
public void run() {
do {
synchronized (counter) {
if (counter.get() % 2 != 0) {
System.out.println("Thread is " + name + ", Counter is = " + counter.getAndAdd(1));
counter.notifyAll();
} else {
try {
counter.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} while (counter.get() <= 10);
}
}
}
Hi in here you have to use java synchronization. Basically synchronization is Java mechanism shared between thread which will block all other threads while one is running. By doing so in your case you can print them sequentially.
You can read the following tutorial to understand it
http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
Be careful though while you use it, because not using carefully might create a deadlock
http://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html
You could achieve this by having the threads acquire a common lock in order to be allowed to print anything.
The "lock" could be some singleton like:
public class Lock {
private static Lock instance;
private static boolean inUse = false;
public static Lock getInstance() {
if(instance == null) {
instance = new Lock();
}
return instance;
}
public boolean acquireLock() {
boolean rv = false;
if(inUse == false) {
inUse = true;
rv = true;
}
return rv;
}
public void releaseLock() {
inUse = false;
}
}
Whenever a thread wants to print it has to call acquireLock() and if it returns true, then it can print. If it returns false, then it has to wait until it returns true. Immediately after printing the thread calls releaseLock() so that the Lock is freed.
I didn't test this code, so use it at your own risk. I just typed it up really quick as it was the idea I was thinking of.
You can read more about locks and their use in synchronization here: http://en.wikipedia.org/wiki/Lock_(computer_science)

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