I am trying to write a multithreaded code. But seriously I can't understand from where can I start. My head is banging also. Please help me.
My task is,
There is one queue of length 1, known as pending_tasks, that contains tasks which requires some processing.
There is another queue of length 1, known as completed_tasks, that contains tasks which completes processing., and ready to deliver.
My implementation thinking,
Firstly make two blocking queues, pending_tasks and completed_tasks.
One thread(producer) always listening for tasks that comes from outside, if gets put into pending_tasks.
One thread(consumer) always ready to take tasks from pending_tasks and starts processing , and after that put into into completed_tasks.
Then again comes to pending_tasks, and whenever any tasks come, start the same processing.
Basically, its a single producer-single consumer problem.
My confusion,
I know that it can be code by using ArrayBlockingQueue and Mutex. But I didn't understand how can I start this. I have good understanding of mutex, I read about mutex from this link, and have good understanding of blockingQueue also, as I read lots of questions on this site.
Can you please give me some implementation guidance, so that I can write this multi-threaded code.
I already wrote some code for the same, but that is not achieve the final goal of my task.
Thanks in advance. Looking for your kind reply.
EDIT NO. 1
Please see my below code. This code works fine, but this code has one functionality missing. Please help me to add that, give some guidance to do that.
Functionality is,
When producer thread puts some value in pending_task queue, then it waits for some time there. If in that time consumer gives the result to consumer, then its OK. Otherwise, it says time out, and producer takes another value and pput that in pending_task queue, and the same process starts.
Please help me in adding above functionality. I think we have to communicate between producer thread and consumer thread, and thread communication is done by using Mutex(I think). Please help me implementing the same
My code,
MultiThread Class
package multithread;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class MultiThread {
public static BlockingQueue<Integer> pending_task;
public static BlockingQueue<Integer> completed_task;
public MultiThread(int length) {
pending_task = new ArrayBlockingQueue<Integer>(length, true);
completed_task = new ArrayBlockingQueue<Integer>(length, true);
}
}
Producer Class
package multithread;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Producer implements Runnable {
#Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
System.out.println("PRODUCER: Try to put value " + i + " in the pending queue");
MultiThread.pending_task.put(i);
System.out.println("PRODUCER: Successfully put value " + i + " in the pending queue, now its turn to consumer");
} catch (InterruptedException ex) {
Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Consumer Class
package multithread;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Consumer implements Runnable {
#Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
System.out.println("CONSUMER: Try to take value from the pending queue");
int val = MultiThread.pending_task.take();
System.out.println("CONSUMER: Successfully take value, and that is " + val);
System.out.println("CONSUMER: Processing starts");
Thread.sleep(1000);
System.out.println("CONSUMER: Processing ends");
System.out.println("CONSUMER: Try to put that that value in completed queue, and the value is " + val);
MultiThread.completed_task.put(val);
System.out.println("CONSUMER: Successfully put into completed queue");
//Serve this value to the corresponding user
} catch (InterruptedException ex) {
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
DeliveryBoy Class
package multithread;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DeliveryBoy implements Runnable {
#Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
System.out.println("DELIVERYBOY: Waiting for the value near completed queue");
int val = MultiThread.completed_task.take();
System.out.println("DELIVERYBOY: Succesfully take value from completed queue and the vlue is " + val);
//Serve this value to the corresponding user
} catch (InterruptedException ex) {
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Test Class
package multithread;
public class Test {
public static void main(String[] args) {
// TODO code application logic here
MultiThread ml = new MultiThread(1);
new Thread(new Producer()).start();
new Thread(new Consumer()).start();
new Thread(new DeliveryBoy()).start();
}
}
From ArrayBlockingQueue#put
public void put(E e)
throws InterruptedException
Inserts the specified element at the tail of this queue, waiting for
**space to become available if the queue is full
From ArrayBlockingQueue#take
public E take()
throws InterruptedException
Description copied from interface: BlockingQueue Retrieves and removes
the head of this queue, waiting if necessary until an element becomes
available.
So all you need to do is call these methods from your threads.
Try this (study the javadoc) and when you have a more specific problem you can ask again.
Related
I'm a bit confused with thread pools and providing an exit condition from a for loop. I haven't found a decent explanation yet on how to do it properly. I have been experimenting with a few possibilities but I'm stuck
I have this piece of code.
#Override
#Transactional(propagation=Propagation.REQUIRED, rollbackFor=Throwable.class)
public void auditAllDomainConfigurationStatuses() {
logger.info("Starting audit of all domain configuration statusses");
int errorStatusCounter = 0;
Map<SubdomainRegistryStatus, List<String>> domainsByStatus = new HashMap<SubdomainRegistryStatus, List<String>>();
List<DomainConfigurationStatus> domains = domainConfigurationStatusDao.findAll();
for (DomainConfigurationStatus domainConfigurationStatus : domains) {
String domainName = domainConfigurationStatus.getDomainName();
DomainConfigurationStatus result = domainConfigurationStatusAuditor.auditDomainConfigurationStatus(domainConfigurationStatus.getId());
addDomainToDomainsByStatusMap(domainsByStatus, result, domainName);
if(SubdomainRegistryStatus.ERROR.equals(result.getStatus())){
errorStatusCounter++;
if(errorStatusCounter >= EMERGENCY_AUDIT_STOP_LIMIT){
logger.error("Emergency audit stop more then " + EMERGENCY_AUDIT_STOP_LIMIT + " records went into status ERROR");
mailEmergencyDomainConfigurationStatusAuditStop();
return;
}
}else{
errorStatusCounter = 0;
}
}
mailDomainConfigurationStatusReport(domainsByStatus);
logger.info("Audit of all domain configuration statusses completed");
}
This code will somewhere call the dns of a domain to fetch it's ip. Then it will update a status in the database. Quite a simple thing. However business wants us to stop the entire process if X times after each other the status translated to ERROR. I managed to write this , quite simple with the above method. However the call to the dns to fetch the ip is slow, I can process about 6 domains per second. We have to process over 32 000 domains. We need to get performance up and for this multithreading is advicable.
So I started with progamming a task, creating a threadpool in spring etc... Then I realized wait that EMERGENCY_AUDIT_STOP_LIMIT how can I still do this if the counter runs over multiple threads ... Without any callback. So I tried with a Callable instead of Runnable so I was working with a Future, then I came to the conclusion WTH am I thinking, the future will block on it's future.get() method so all I'm going to end up with is a method just as slow or slower then my original implementation.
So this was my road sofar and I'm now a bit blocked, a Runnable can't throw an exception so passing the counter to the task won't work either and a Callable will block so that's no option either.
If any multithreading guru has an idea I would be very grateful. Below was my latest attempt , it wasn't broken but just as slow as my above method.
#Override
#Transactional(propagation=Propagation.REQUIRED, rollbackFor=Throwable.class)
public void auditAllDomainConfigurationStatuses() throws InterruptedException, ExecutionException {
logger.info("Starting audit of all domain configuration statusses");
int errorStatusCounter = 0;
Map<SubdomainRegistryStatus, List<String>> domainsByStatus = new HashMap<SubdomainRegistryStatus, List<String>>();
List<DomainConfigurationStatus> domains = domainConfigurationStatusDao.findAll();
for (DomainConfigurationStatus domainConfigurationStatus : domains) {
try {
Future<Integer> futureResult = taskExecutor.submit(new DomainConfigurationAuditTask(errorStatusCounter, domainConfigurationStatusAuditor, domainConfigurationStatus.getId(), domainsByStatus, EMERGENCY_AUDIT_STOP_LIMIT));
futureResult.get();
}
catch (Exception e) {
logger.error("Emergency audit stop more then " + EMERGENCY_AUDIT_STOP_LIMIT + " records went into status ERROR");
mailEmergencyDomainConfigurationStatusAuditStop();
return;
}
}
mailDomainConfigurationStatusReport(domainsByStatus);
logger.info("Audit of all domain configuration statusses completed");
}
Here's a pretty simple solution. Basically, the tasks for doing some work (i.e. DNS lookup) is completely isolated and parallelizable. Part of it's work after a success or failure is to submit a success boolean to another ExecutoService with a fixed size of 1, which can do whatever error condition checking you want.
In this case, it's simply incrementing an integer with consecutive errors, until a max condition is reached and then sets an error condition which the work threads (DNS lookups) all check first for a fail-fast approach, so all queued up tasks will exit quickly after the error condition is met.
This ends up being pretty simple way for tracking consecutive errors in a multi-threaded scenario like this, as you're single-threading a check on the responses
I can think of a much more elegant solution using Java 8's CompletableFuture, but sounds like that is off the table
package so.thread.errcondition;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static Random rand = new Random();
public static ExecutorService workers = Executors.newFixedThreadPool(5);
// NOTE, this executor has a FIXED size of 1 for in-order processing
public static ExecutorService watcher = Executors.newFixedThreadPool(1);
public static AtomicBoolean errorCondition = new AtomicBoolean(false);
public static AtomicInteger errorCount = new AtomicInteger(0);
public static Integer MAX_ERRORS = 5;
public static void main(String[] args) throws Exception {
int jobs = 1000;
for (int i = 0; i < jobs; i++) {
workers.submit(getWork());
}
Thread.sleep(TimeUnit.SECONDS.toMillis(5));
}
// parallelizable task, the number of parallel workers is irrelevant
public static Runnable getWork() {
return new Runnable() {
#Override
public void run() {
// fail fast
if (errorCondition.get()) {
System.out.println("%%% MAX_ERRORS of [" + MAX_ERRORS + "] occurred, skipping task");
return;
}
// do work
if (rand.nextBoolean()) {
// GOOD JOB
System.out.println("+++ GOOD RESULT");
submitDoneTask(true);
} else {
// ERROR
System.out.println("*** BAD RESULT");
submitDoneTask(false);
}
}
};
}
public static void submitDoneTask(final boolean success) {
watcher.submit(new Runnable() {
#Override
public void run() {
if (!errorCondition.get() && success) {
errorCount.set(0);
} else {
int errors = errorCount.incrementAndGet();
if (errors >= MAX_ERRORS) {
errorCondition.set(true);
}
}
}
});
}
}
I'm using AMQP to queue multiple threads doing graph searches. The graph is not modified except on a regular interval by a separate thread. What's the best concurrency model to wait for all active searches to complete, block those threads, and allow the update thread to modify the graph before unblocking the search threads?
I've been reading through http://docs.oracle.com/javase/tutorial/essential/concurrency/ but I can't seem to find anything that exactly fits my model.
Any suggestions?
thanks!
edit: i'm using ExecutorService to handle the threads.
Do you really need to block? Maybe non-blocking copy-on-write could suffice.
Updating thread should make a clone of current graph structure and apply updates on the clone. Once it is done with updates the new graph should be announced - just overwriting the shared reference.
Searching thread should save the graph reference to local variable or scope once and use it. Shared graph is never modified so there is no need for any locking and waiting.
Pros:
no locking and waiting of readers,
if update fails, readers still work with old structure
ideal for long running and occasional updates where there is more reads than updates
garbage collector takes care of old graphs
Cons:
some readers may operate on old data if they started before the update - this may be resolved by checking if original reference to graph changed and eventually restarting the whole operation.
multiple writers may introduce conflicts in graph, but it may be resolved by several conflict resolution techniques, the easiest is to ignore previous changes and overwrite ("Take mine").
It is also possible to apply copy-on-write only to part of the graph. Especially if graph is memory consuming structure. However it is quite hard topic - see MVCC and STM (Software Transactional Memory).
I'm not familiar with AMQP but this is a producer/consumer problem so there are several ways to deal with this in Java. This is a really quick and dirty example with Futures and ReentrantLock:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo {
private static Random rand = new Random();
private static final Lock lock = new ReentrantLock();
private static boolean updating = false;
private static List<Future<Integer>> futureList = new ArrayList<Future<Integer>>();
private static ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private static Callable<Integer> callable = new Callable<Integer>() {
#Override
public Integer call() {
return rand.nextInt();
}
};
private static void doUpdate() {
if (lock.tryLock()) {
updating = true;
try {
for (Future<Integer> future : futureList) {
System.out.println(future.get());
}
futureList.clear();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println();
lock.unlock();
updating = false;
}
}
}
public static void main(String[] args) throws Exception {
// submitter thread
new Thread(new Runnable() {
#Override
public void run() {
int submitCount = 0;
while (submitCount < 10) {
if (!updating) {
futureList.add(pool.submit(callable));
submitCount++;
}
try {
Thread.sleep(1000); // arbitrary
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
// update thread
new Thread(new Runnable() {
#Override
public void run() {
int updateCount = 0;
while (updateCount < 5) {
doUpdate();
updateCount++;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
I set the update thread to half the frequency of the submit thread. So if you run this you'll see the updater peel off two integers each time it runs. The submit thread has to wait until the updater releases the lock.
There are other approaches - look into the BlockingQueue interface: you may want to experiment.
I am working on a project in which I will be having different Bundles. Let's take an example, Suppose I have 5 Bundles and each of those bundles will have a method name process.
Now currently, I am calling the process method of all those 5 bundles sequentially, one by one and then I am writing to the database. But that's what I don't want.
Below are the things that I am looking for-
I need to call all those 5 Bundles process method in parallel using multithreaded code and then write to the database. I am not sure what is the right way to do that? Should I have five thread? One thread for each bundle? But what will happen in that scenario, suppose if I have 50 bundles, then I will have 50 threads?
And also, I want to have timeout feature as well. If any bundles is taking lot of time than the threshold setup by us, then it should get timeout and log as an error that this bundle has taken lot of time.
I hope the question is clear enough.
Below is the code I have so far which is calling process method of each bundles sequentially one by one.
public void callBundles(final Map<String, Object> eventData) {
final Map<String, String> outputs = (Map<String, String>)eventData.get(Constants.HOLDER);
for (final BundleRegistration.BundlesHolderEntry entry : BundleRegistration.getInstance()) {
// calling the process method of a bundle
final Map<String, String> response = entry.getPlugin().process(outputs);
// then write to the database.
System.out.println(response);
}
}
I am not sure what is the best and efficient way to do this? And I don't want to write sequentially. Because, in future, it might be possible that I will have more than 5 bundles.
Can anyone provide me an example of how can I do this? I have tried doing it but somehow it is not the way I am looking for.
Any help will be appreciated on this. Thanks.
Update:-
This is what I came up with-
public void callBundles(final Map<String, Object> eventData) {
// Three threads: one thread for the database writer, five threads for the plugin processors
final ExecutorService executor = Executors.newFixedThreadPool(5);
final BlockingQueue<Map<String, String>> queue = new LinkedBlockingQueue<Map<String, String>>();
#SuppressWarnings("unchecked")
final Map<String, String> outputs = (Map<String, String>)eventData.get(Constants.EVENT_HOLDER);
for (final BundleRegistration.BundlesHolderEntry entry : BundleRegistration.getInstance()) {
executor.submit(new Runnable () {
public void run() {
final Map<String, String> response = entry.getPlugin().process(outputs);
// put the response map in the queue for the database to read
queue.offer(response);
}
});
}
Future<?> future = executor.submit(new Runnable () {
public void run() {
Map<String, String> map;
try {
while(true) {
// blocks until a map is available in the queue, or until interrupted
map = queue.take();
// write map to database
System.out.println(map);
}
} catch (InterruptedException ex) {
// IF we're catching InterruptedException then this means that future.cancel(true)
// was called, which means that the plugin processors are finished;
// process the rest of the queue and then exit
while((map = queue.poll()) != null) {
// write map to database
System.out.println(map);
}
}
}
});
// this interrupts the database thread, which sends it into its catch block
// where it processes the rest of the queue and exits
future.cancel(true); // interrupt database thread
// wait for the threads to finish
try {
executor.awaitTermination(5, TimeUnit.MINUTES);
} catch (InterruptedException e) {
//log error here
}
}
But I was not able to add any timeout feature into this yet.. And also If I am run my above code as it is, then also it is not running.. I am missing anything?
Can anybody help me with this?
This is BASIC example, partially based on the solution presented in ExecutorService that interrupts tasks after a timeout.
You will have to figure out the best way to get this implemented into your own code. Use it only as a guide!
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ExecutorExample {
// This is used to "expire" long running tasks
protected static final ScheduledExecutorService EXPIRE_SERVICE = Executors.newScheduledThreadPool(1);
// This is used to manage the bundles and process them as required
protected static final ExecutorService BUNDLES_SERVICE = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
// A list of the future tasks created by the BUNDLES_SERVICE.
// We need this so we can monitor the progress of the output
List<Future<String>> futureTasks = new ArrayList<>(100);
// This is a list of all the tasks that have either completed
// or begin canceled...we want these so we can determine
// the results...
List<Future<String>> completedTasks = new ArrayList<>(100);
// Add all the Bundles to the BUNDLES_SERVICE
for (int index = 0; index < 100; index++) {
Bundle bundle = new Bundle();
// We need a reference to the future so we can cancel it if we
// need to
Future<String> futureBundle = BUNDLES_SERVICE.submit(bundle);
// Set this bundles future, see Bundle for details
bundle.setFuture(futureBundle);
// Add it to our monitor queue...
futureTasks.add(futureBundle);
}
// Basically we are going to move all completed/canceled bundles
// from the "active" to the completed list and wait until there
// are no more "active" tasks
while (futureTasks.size() > 0) {
try {
// Little bit of a pressure release...
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
// Check all the bundles...
for (Future<String> future : futureTasks) {
// If it has completed or was cancelled, move it to the completed
// list. AKAIK, isDone will return true is isCancelled is true as well,
// but this illustrates the point
if (future.isCancelled() || future.isDone()) {
completedTasks.add(future);
}
}
// Remove all the completed tasks from the future tasks lists
futureTasks.removeAll(completedTasks);
// Some idea of progress...
System.out.println("Still have " + futureTasks.size() + " outstanding tasks...");
}
// Dump the results...
int index = 0;
for (Future<String> future : completedTasks) {
index++;
System.out.print("Task " + index);
if (future.isCancelled()) {
System.out.println(" was canceled");
} else if (future.isDone()) {
try {
System.out.println(" completed with " + future.get());
} catch (Exception ex) {
System.out.println(" failed because of " + ex.getMessage());
}
}
}
System.exit(0);
}
public static class ExpireBundle implements Runnable {
private final Future futureBundle;
public ExpireBundle(Future futureBundle) {
this.futureBundle = futureBundle;
}
#Override
public void run() {
futureBundle.cancel(true);
}
}
public static class Bundle implements Callable<String> {
private volatile Future<String> future;
#Override
public String call() throws Exception {
// This is the tricky bit. In order to cancel a task, we
// need to wait until it runs, but we also need it's future...
// We could use another, single threaded queue to do the job
// but that's getting messy again and it won't provide the information
// we need back to the original calling thread that we are using
// to schedule and monitor the threads...
// We need to have a valid future before we can continue...
while (future == null) {
Thread.sleep(250);
}
// Schedule an expiry call for 5 seconds from NOW...this is important
// I original thought about doing this when I schedule the original
// bundle, but that precluded the fact that some tasks would not
// have started yet...
EXPIRE_SERVICE.schedule(new ExpireBundle(future), 5, TimeUnit.SECONDS);
// Sleep for a random amount of time from 1-10 seconds
Thread.sleep((long) (Math.random() * 9000) + 1000);
return "Happy";
}
protected void setFuture(Future<String> future) {
this.future = future;
}
}
}
Also. I had thought of using ExecutorService#invokeAll to wait for the tasks to complete, but this precluded the ability to timeout tasks. I don't like having to feed the Future into the Callable, but no other solution seemed to come to mind that would allow me to get the results from the submitted Future.
I don't know why my get method doesn't work. It returns " ".
I have Producer and Consumer classes that use this class and Buffer interface that just have set and get methods. Producer reads from file and Consumer writes into another file. Both Producer and Consumer uses thread.
Please help me. Thanks in advance.
import java.util.Stack;
public class synchronizedFile implements Buffer {
public Stack<String> StackBuffer = new Stack<String>();
public void set(String value) {
synchronized (StackBuffer) {
if (StackBuffer.size() <= 15) {
StackBuffer.push(value);
System.out.println(StackBuffer.toString());
StackBuffer.notifyAll();
System.out.println("Consumer notify");
} else {
try {
System.out.println("Produser is waitting--------------------------------");
StackBuffer.wait();
System.out.println("Consumer tries to write");
set(value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public String get() throws InterruptedException {
String Flag = " ";
synchronized (StackBuffer) {
if (!StackBuffer.isEmpty()) {
Flag = StackBuffer.firstElement();
StackBuffer.remove(StackBuffer.firstElement());
StackBuffer.notifyAll();
System.out.println("Producer notify");
return Flag;
} else {
StackBuffer.wait();
System.out.println("Consumer is waitting --------------------");
get();
}
}
return Flag;
}
}
You are at least missing a Flag = get() in your else branch of the get() method.
Apart from that consider using a BlockingQueue, there are implementations in java.util.concurrent that do the heavy lifting in concurrent programming for you. Using the low level constructs wait and notify is error prone. Without checking it thoroughly, I would be surprised if your implementation would be correct.
You wait and notify for two different status: full and empty. Therefore, you must use two separate lock objects. This has been covered a short while ago here.
Basically, if you are not implementing this for the sake of using the Stack class or some kind of assignment, use a BlockingQueue from java.util.concurrent.
Here you call get() recursively but throw away its result:
StackBuffer.wait();
System.out.println("Consumer is waitting --------------------");
get();
Something like Flag = get(); or return get();would be more appropriate.
(Also I'm not sure if entering synchronized section twice with doing wait is valid. Maybe it is, I'm just unsure).
In the Observer Design Pattern, the subject notifies all observers by calling the update() operation of each observer. One way of doing this is
void notify() {
for (observer: observers) {
observer.update(this);
}
}
But the problem here is each observer is updated in a sequence and update operation for an observer might not be called till all the observers before it is updated. If there is an observer that has an infinite loop for update then all the observer after it will never be notified.
Question:
Is there a way to get around this problem?
If so what would be a good example?
The problem is the infinite loop, not the one-after-the-other notifications.
If you wanted things to update concurrently, you'd need to fire things off on different threads - in which case, each listener would need to synchronize with the others in order to access the object that fired the event.
Complaining about one infinite loop stopping other updates from happening is like complaining that taking a lock and then going into an infinite loop stops others from accessing the locked object - the problem is the infinite loop, not the lock manager.
Classic design patterns do not involve parallelism and threading. You'd have to spawn N threads for the N observers. Be careful though since their interaction to this will have to be done in a thread safe manner.
You could make use of the java.utils.concurrent.Executors.newFixedThreadPool(int nThreads) method, then call the invokeAll method (could make use of the one with the timout too to avoid the infinite loop).
You would change your loop to add a class that is Callable that takes the "observer" and the "this" and then call the update method in the "call" method.
Take a look at this package for more info.
This is a quick and dirty implementation of what I was talking about:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Main
{
private Main()
{
}
public static void main(final String[] argv)
{
final Watched watched;
final List<Watcher> watchers;
watched = new Watched();
watchers = makeWatchers(watched, 10);
watched.notifyWatchers(9);
}
private static List<Watcher> makeWatchers(final Watched watched,
final int count)
{
final List<Watcher> watchers;
watchers = new ArrayList<Watcher>(count);
for(int i = 0; i < count; i++)
{
final Watcher watcher;
watcher = new Watcher(i + 1);
watched.addWatcher(watcher);
watchers.add(watcher);
}
return (watchers);
}
}
class Watched
{
private final List<Watcher> watchers;
{
watchers = new ArrayList<Watcher>();
}
public void addWatcher(final Watcher watcher)
{
watchers.add(watcher);
}
public void notifyWatchers(final int seconds)
{
final List<Watcher> currentWatchers;
final List<WatcherCallable> callables;
final ExecutorService service;
currentWatchers = new CopyOnWriteArrayList<Watcher>(watchers);
callables = new ArrayList<WatcherCallable>(currentWatchers.size());
for(final Watcher watcher : currentWatchers)
{
final WatcherCallable callable;
callable = new WatcherCallable(watcher);
callables.add(callable);
}
service = Executors.newFixedThreadPool(callables.size());
try
{
final boolean value;
service.invokeAll(callables, seconds, TimeUnit.SECONDS);
value = service.awaitTermination(seconds, TimeUnit.SECONDS);
System.out.println("done: " + value);
}
catch (InterruptedException ex)
{
}
service.shutdown();
System.out.println("leaving");
}
private class WatcherCallable
implements Callable<Void>
{
private final Watcher watcher;
WatcherCallable(final Watcher w)
{
watcher = w;
}
public Void call()
{
watcher.update(Watched.this);
return (null);
}
}
}
class Watcher
{
private final int value;
Watcher(final int val)
{
value = val;
}
public void update(final Watched watched)
{
try
{
Thread.sleep(value * 1000);
}
catch (InterruptedException ex)
{
System.out.println(value + "interupted");
}
System.out.println(value + " done");
}
}
I'd be more concerned about the observer throwing an exception than about it looping indefinitely. Your current implementation would not notify the remaining observers in such an event.
1. Is there a way to get around this problem?
Yes, make sure the observer work fine and return in a timely fashion.
2. Can someone please explain it with an example.
Sure:
class ObserverImpl implements Observer {
public void update( Object state ) {
// remove the infinite loop.
//while( true ) {
// doSomething();
//}
// and use some kind of control:
int iterationControl = 100;
int currentIteration = 0;
while( curentIteration++ < iterationControl ) {
doSomething();
}
}
private void doSomething(){}
}
This one prevent from a given loop to go infinite ( if it makes sense, it should run at most 100 times )
Other mechanism is to start the new task in a second thread, but if it goes into an infinite loop it will eventually consume all the system memory:
class ObserverImpl implements Observer {
public void update( Object state ) {
new Thread( new Runnable(){
public void run() {
while( true ) {
doSomething();
}
}
}).start();
}
private void doSomething(){}
}
That will make the that observer instance to return immediately, but it will be only an illusion, what you have to actually do is to avoid the infinite loop.
Finally, if your observers work fine but you just want to notify them all sooner, you can take a look at this related question: Invoke a code after all mouse event listeners are executed..
All observers get notified, that's all the guarantee you get.
If you want to implement some fancy ordering, you can do that:
Connect just a single Observer;
have this primary Observer notify his friends in an order you define in code or by some other means.
That takes you away from the classic Observer pattern in that your listeners are hardwired, but if it's what you need... do it!
If you have an observer with an "infinite loop", it's no longer really the observer pattern.
You could fire a different thread to each observer, but the observers MUST be prohibited from changing the state on the observed object.
The simplest (and stupidest) method would simply be to take your example and make it threaded.
void notify() {
for (observer: observers) {
new Thread(){
public static void run() {
observer.update(this);
}
}.start();
}
}
(this was coded by hand, is untested and probably has a bug or five--and it's a bad idea anyway)
The problem with this is that it will make your machine chunky since it has to allocate a bunch of new threads at once.
So to fix the problem with all the treads starting at once, use a ThreadPoolExecutor because it will A) recycle threads, and B) can limit the max number of threads running.
This is not deterministic in your case of "Loop forever" since each forever loop will permanently eat one of the threads from your pool.
Your best bet is to not allow them to loop forever, or if they must, have them create their own thread.
If you have to support classes that can't change, but you can identify which will run quickly and which will run "Forever" (in computer terms I think that equates to more than a second or two) then you COULD use a loop like this:
void notify() {
for (observer: observers) {
if(willUpdateQuickly(observer))
observer.update(this);
else
new Thread(){
public static void run() {
observer.update(this);
}
}.start();
}
}
Hey, if it actually "Loops forever", will it consume a thread for every notification? It really sounds like you may have to spend some more time on your design.