looking for java concurrency model suggestion - java

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.

Related

Java happens-before consistent thread view on two ConcurrentMaps

I have a java class to handle a multithreaded subscription service. By implementing the Subscribable interface, tasks can be submitted to the service and periodically executed. A sketch of the code is seen below:
import java.util.concurrent.*;
public class Subscribtions {
private ConcurrentMap<Subscribable, Future<?>> futures = new ConcurrentHashMap<Subscribable, Future<?>>();
private ConcurrentMap<Subscribable, Integer> cacheFutures = new ConcurrentHashMap<Subscribable, Integer>();
private ScheduledExecutorService threads;
public Subscribtions() {
threads = Executors.newScheduledThreadPool(16);
}
public void subscribe(Subscribable subscription) {
Runnable runnable = getThread(subscription);
Future<?> future = threads.scheduleAtFixedRate(runnable, subscription.getInitialDelay(), subscription.getPeriod(), TimeUnit.SECONDS);
futures.put(subscription, future);
}
/*
* Only called from controller thread
*/
public void unsubscribe(Subscribable subscription) {
Future<?> future = futures.remove(subscription); //1. Might be removed by worker thread
if (future != null)
future.cancel(false);
else {
//3. Worker-thread view := cacheFutures.put() -> futures.remove()
//4. Controller-thread has seen futures.remove(), but has it seen cacheFutures.put()?
}
}
/*
* Only called from worker threads
*/
private void delay(Runnable runnable, Subscribable subscription, long delay) {
cacheFutures.put(subscription, 0); //2. Which is why it is cached first
Future<?> currentFuture = futures.remove(subscription);
if (currentFuture != null) {
currentFuture.cancel(false);
Future<?> future = threads.scheduleAtFixedRate(runnable, delay, subscription.getPeriod(), TimeUnit.SECONDS);
futures.put(subscription, future);
}
}
private Runnable getThread(Subscribable subscription) {
return new Runnable() {
public void run() {
//Do work...
boolean someCondition = true;
long someDelay = 100;
if (someCondition) {
delay(this, subscription, someDelay);
}
}
};
}
public interface Subscribable {
long getInitialDelay();
long getPeriod();
}
}
So the class permits to:
Subscribe to new tasks
Unsubscribe from existing tasks
Delay a periodically executed task
Subscriptions are added/removed by an external controlling thread, but delays are incurred only by the internal worker threads. This could happen, if for instance a worker thread found no update from the last execution or e.g. if the thread only needs to execute from 00.00 - 23.00.
My problem is that a worker thread may call delay() and remove its future from the ConcurrentMap, and the controller thread may concurrently call unsubscribe(). Then if the controller thread checks the ConcurrentMap before the worker thread has put in a new future, the unsubscribe() call will be lost.
There are some (not exhaustive list perhaps) solutions:
Use a lock between the delay() and unsubscribe() methods
Same as above, but one lock per subscribtion
(preferred?) Use no locks, but "cache" removed futures in the delay() method
As for the third solution, since the worker-thread has established the happens-before relationship cacheFutures.put() -> futures.remove(), and the atomicity of ConcurrentMap makes the controller thread see futures.remove(), does it also see the same happens-before relationship as the worker thread? I.e. cacheFutures.put() -> futures.remove()? Or does the atomicity only hold for the futures map with updates to other variables being propagated later?
Any other comments are also welcome, esp. considering use of the volatile keyword. Should the cache-map be declared volatile? thanks!
One lock per subscription would require you to maintain yet another map, and possibly thereby to introduce additional concurrency issues. I think that would be better avoided. The same applies even more so to caching removed subscriptions, plus that affords the added risk of unwanted resource retention (and note that it's not the Futures themselves that you would need to cache, but rather the Subscribables with which they are associated).
Any way around, you will need some kind of synchronization / locking. For example, in your option (3) you need to avoid an unsubscribe() for a given subscription happening between delay() caching that subscription and removing its Future. The only way you could avoid that without some form of locking would be if you could use just one Future per subscription, kept continuously in place from the time it is enrolled by subscribe() until it is removed by unsubscribe(). Doing so is not consistent with the ability to delay an already-scheduled subscription.
As for the third solution, since the worker-thread has established the happens-before relationship cacheFutures.put() -> futures.remove(), and the atomicity of ConcurrentMap makes the controller thread see futures.remove(), does it also see the same happens-before relationship as the worker thread?
Happens-before is a relationship between actions in an execution of a program. It is not specific to any one thread's view of the execution.
Or does the atomicity only hold for the futures map with updates to other variables being propagated later?
The controller thread will always see the cacheFutures.put() performed by an invocation of delay() occuring before the futures.remove() performed by that same invocation. I don't think that helps you, though.
Should the cache-map be declared volatile?
No. That would avail nothing, because although the contents of that map change, the map itself is always the same object, and the reference to it does not change.
You could consider having subscribe(), delay(), and unsubscribe() each synchronize on the Subscribable presented. That's not what I understood you to mean about having a lock per subscription, but it is similar. It would avoid the need for a separate data structure to maintain such locks. I guess you could also build locking methods into the Subscribable interface if you want to avoid explicit synchronization.
You have a ConcurrentMap but you aren't using it. Consider something along these lines:
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
final class SO33555545
{
public static void main(String... argv)
throws InterruptedException
{
ScheduledExecutorService workers = Executors.newScheduledThreadPool(16);
Subscriptions sub = new Subscriptions(workers);
sub.subscribe(() -> System.out.println("Message received: A"));
sub.subscribe(() -> System.out.println("Message received: B"));
Thread.sleep(TimeUnit.SECONDS.toMillis(30));
workers.shutdown();
}
}
final class Subscriptions
{
private final ConcurrentMap<Subscribable, Task> tasks = new ConcurrentHashMap<>();
private final ScheduledExecutorService workers;
public Subscriptions(ScheduledExecutorService workers)
{
this.workers = workers;
}
void subscribe(Subscribable sub)
{
Task task = new Task(sub);
Task current = tasks.putIfAbsent(sub, task);
if (current != null)
throw new IllegalStateException("Already subscribed");
task.activate();
}
private Future<?> schedule(Subscribable sub)
{
Runnable task = () -> {
sub.invoke();
if (Math.random() < 0.25) {
System.out.println("Delaying...");
delay(sub, 5);
}
};
return workers.scheduleAtFixedRate(task, sub.getPeriod(), sub.getPeriod(), TimeUnit.SECONDS);
}
void unsubscribe(Subscribable sub)
{
Task task = tasks.remove(sub);
if (task != null)
task.cancel();
}
private void delay(Subscribable sub, long delay)
{
Task task = new Task(sub);
Task obsolete = tasks.replace(sub, task);
if (obsolete != null) {
obsolete.cancel();
task.activate();
}
}
private final class Task
{
private final FutureTask<Future<?>> future;
Task(Subscribable sub)
{
this.future = new FutureTask<>(() -> schedule(sub));
}
void activate()
{
future.run();
}
void cancel()
{
boolean interrupted = false;
while (true) {
try {
future.get().cancel(false);
break;
}
catch (ExecutionException ignore) {
ignore.printStackTrace(); /* Cancellation is unnecessary. */
break;
}
catch (InterruptedException ex) {
interrupted = true; /* Keep waiting... */
}
}
if (interrupted)
Thread.currentThread().interrupt(); /* Reset interrupt state. */
}
}
}
#FunctionalInterface
interface Subscribable
{
default long getPeriod()
{
return 4;
}
void invoke();
}

HealthChecker for Java Process

I want to create a health checker, which will check the health of a java process. My process does a lot of things and is multi threaded. Various exceptions could be thrown, like Service / SQL / IO, etc. My plan is to call the HealthChecker to check for the process, from the catch block, in the individual threads. This will check for all the different healths, and in the case where there is any issue it will pause the threads, and log appropriately. There will be other processes which will read the logs by the process, and alert support to take appropriate actions.
Below is the general structure of the java process.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Schedular {
private static int numOfTasks = 10 ;
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(5);
while(true){
for(int i=0;i<numOfTasks;i++){
service.execute(new Workers());
}
}
}
}
class Workers implements Runnable{
#Override
public void run() {
/*
* This can throw different exceptions , eg:
*/
try{
}catch(Exception e){
e.printStackTrace();
HealthChecker.checkHealth();
}
}
}
class HealthChecker{
public static void checkHealth() {
//Check health and then , log and pause all the threads
}
}
I am not able to figure out a way to pause all the threads. If there is a db exception I want all the threads to pause. I am requesting some suggestions.
You need a way to block the threads until some event occurs that allows the threads to continue. I see some major issues with the code:
1) The while(true) in your main thread might lead to a StackOverflowError. With each iteration of the while loop, you will add 10 more threads to the executor, and this will just continue unbounded.
2) There is no loop in your run() so that even if an exception is caught and we wait for the HealthCheck, the run() method would still exit. While a loop is not needed in your run() if you can constantly execute new Threads from your main thread to take the place of the terminated one, but that logic is not presently there in the main loop.
But setting those concerns aside here is one way to block worker threads until some event (presumably a HealthCheck all clear) occurs.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Schedular {
private static int numOfTasks = 10 ;
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(5);
HealtchChecker hChecker = new HealthChecker();
for(int i=0;i<numOfTasks;i++){
service.execute(new Workers(hChecker));
}
}
}
class Workers implements Runnable{
private HealtchChecker hChecker;
public Workers(HealtchChecker hChecker){
this.hChecker = hChecker;
}
#Override
public void run() {
/*
* This can throw different exceptions , eg:
*/
while(true) {
try{
}catch (InterruptedException ie) {
throw ie;
}catch(Exception e){
e.printStackTrace();
HealthChecker.checkHealth();
}
}
}
}
class HealthChecker implements Runnable {
private final Semaphore semaphore = new Semaphore(1, true);
public void checkHealth() {
try {
semaphore.acquire();
} finally {
semaphore.release();
}
}
#Override
public void run(){
//code to check for errors that cause threads to pause.
if (inErrorState) {
semaphore.acquire();
} else {
semaphore.release();
}
}
}
A few things worth mentioning.
1) The main thread only creates 10 threads, versus an unbounded amount. You can adjust this as needed.
2) The Worker thread is long lived, meaning it will continue running even if it encounters Exceptions, except for an InterruptException.
3) HealthCheck is no longer a static object. it is instead a shared object.
4) HealthCheck is a runnable that can be executed in its own thread for monitoring for errors. I did not add the code to execute this thread.
5) HealCheck uses a Semaphore to cause the threads to block until the error state is cleared. I looked for other objects that can do this, like CountDownLatch or CyclicBarrier or Phaser, but this one came closest to giving us what we need to block all the threads from one point (the run() method).
Its not perfect but I think it gets you a little bit closer to what you want.
You're venturing pretty far afield from best practices, but you didn't ask about best practices for monitoring the health of threads - so I won't answer that question. Instead, I'll just answer the question you asked: how can I pause a set of threads managed by an ExecutorService?
Assuming that your Workers.run() will eventually end without intervention (in other words, it's not in an infinite loop - intentional or otherwise), the right thing to do is to call service.shutdown() (where service is your instance of ExecutorService). To do this, you can pass service in to HealthCheck.healthCheck() as a new parameter. Calling shutdown() will allow the currently-running threads to complete, then stop the executor.
If Workers.run() will not naturally complete, best practice says that you need to change your code such that it will. There is a Thread.stop() method you can call to halt the thread and a Thread.suspend() method you can call to suspend the thread. Both of these are double-bad ideas for you to use for two reasons:
They are Deprecated and will leave the Threads in a super-unhealthy state. You will have very difficult problems in the future if you use them.
You are using ExecutorService. That means you are delegating thread management to that class. If you go messing with the state of the Threads underneath ExecutorService, it can't manage the thread pool for you and, again, you will have very difficult problems in the future.

How to change a variable via a worker thread

Is there an elegant way to do that? Or it can always be avoided because one can use a better design patter?
import java.util.ArrayList;
import java.util.List;
public class ForTest {
List<String> ls = new ArrayList<String>();
public static void main(String[] args) {
ForTest forTest=new ForTest();
System.out.println(forTest.ls.size());
new Thread(new Worker(forTest.ls)).start();
//size() does not change at all
System.out.println(forTest.ls.size());
}
}
class Worker implements Runnable{
List<String> list;
public Worker(List<String> li) {
this.list = li;
}
public void run(){
this.list.add("newItem");
}
}
There are several issues with your code (in particular you use ArrayList which is not thread safe without proper synchronization).
But the most obvious one is that the second println statement is almost always going to be called before your run method has had a chance to be executed.
You need to make your main thread sleep() for a while. The size() is getting called before the new Thread gets a chance to update it.
new Thread(new Worker(forTest.ls)).start();
Thread.sleep(2000);
System.out.println(forTest.ls.size());
An even better way would be to join() on to the worker thread. This would make the main thread automatically wake up when the worker is finished.
Thread worker = new Thread(new Worker(forTest.ls));
worker.start();
worker.join();
System.out.println(forTest.ls.size());
In addition to that make use of a synchronized ArrayList to prevent a race condition if the List would be shared and modified by multiple threads.
List<String> ls = Collections.synchronizedList(new ArrayList<String>());
You seem to be missing the idea of Threading. Your code will not work because your worker has likely not updated ls by the time you print it. If you're using threading, the threads need to communicate state. This is all quite complex, I suggest you read the java tutorials on threading http://docs.oracle.com/javase/tutorial/essential/concurrency/
Please note that ArrayList is not synchronized, but Vector is. You cannot expect the worker to run just a moment after you started its thread. That's why the list size is not changed yet. I guess this is not your complete example, so it is difficult to help you. (If this was your complete example I would wonder why you bother implementing a multi-threaded solution.)
For knowing when the worker finished you could join the threads.
wait for the new thread to actually start running your code + make forTest final to be able to access it (also use a thread-safe collection - best non-synchronous a.k.a. non-blocking) e.g.
import java.util.Collection;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ForTest {
Collection<String> ls = new ConcurrentLinkedQueue<String>();
public static void main(String[] args) throws InterruptedException {
final ForTest forTest = new ForTest();
System.out.println(forTest.ls.size());
int threads = 10;
for ( int i=0; i<threads; i++ ) {
new Thread(new Runnable() {
#Override
public void run() {
forTest.ls.add("newItem");
}
}).start();
}
Thread.sleep(1000);// wait for it !
System.out.println(forTest.ls.size()); // 10 unless your threads are really slow
}
}

How to indefinitely pause a thread in Java and later resume it?

Maybe this question has been asked many times before, but I never found a satisfying answer.
The problem:
I have to simulate a process scheduler, using the round robin strategy. I'm using threads to simulate processes and multiprogramming; everything works fine with the JVM managing the threads. But the thing is that now I want to have control of all the threads so that I can run each thread alone by a certain quantum (or time), just like real OS processes schedulers.
What I'm thinking to do:
I want have a list of all threads, as I iterate the list I want to execute each thread for their corresponding quantum, but as soon the time's up I want to pause that thread indefinitely until all threads in the list are executed and then when I reach the same thread again resume it and so on.
The question:
So is their a way, without using deprecated methods stop(), suspend(), or resume(), to have this control over threads?
Yes, there is:
Object.wait( ), Object.notify() and a bunch of other much nicer synchronization primitives in java.util.concurrent.
Who said Java is not low level enough?
Here is my 3 minute solution. I hope it fits your needs.
import java.util.ArrayList;
import java.util.List;
public class ThreadScheduler {
private List<RoundRobinProcess> threadList
= new ArrayList<RoundRobinProcess>();
public ThreadScheduler(){
for (int i = 0 ; i < 100 ; i++){
threadList.add(new RoundRobinProcess());
new Thread(threadList.get(i)).start();
}
}
private class RoundRobinProcess implements Runnable{
private final Object lock = new Object();
private volatile boolean suspend = false , stopped = false;
#Override
public void run() {
while(!stopped){
while (!suspend){
// do work
}
synchronized (lock){
try {
lock.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
}
public void suspend(){
suspend = true;
}
public void stop(){
suspend = true;stopped = true;
synchronized (lock){
lock.notifyAll();
}
}
public void resume(){
suspend = false;
synchronized (lock){
lock.notifyAll();
}
}
}
}
Please note that "do work" should not be blocking.
Short answer: no. You don't get to implement a thread scheduler in Java, as it doesn't operate at a low enough level.
If you really do intend to implement a process scheduler, I would expect you to need to hook into the underlying operating system calls, and as such I doubt this will ever be a good idea (if remotely possible) in Java. At the very least, you wouldn't be able to use java.lang.Thread to represent the running threads so it may as well all be done in a lower-level language like C.

Observer Design Pattern

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.

Categories