Search code examples
javamultithreadingobserver-pattern

Java Threads with Observer pattern for long operations


In my application, I have two threads given ThreadA and ThreadB. ThreadA is a thread that holds and manipulates some data (the producer) and ThreadB is the corresponding consumer thread that reads from ThreadA (read-only).
I want to achieve that ThreadB informs ThreadA to update the data (which may take some time) and when the data is changed, ThreadB should get/request it from ThreadA. As long as ThreadA has not finished updating the data, ThreadB shouldn't wait but continue his work with the current (old) data he has. Now my idea was to use the observer pattern to inform ThreadB that ThreadA has finished updating

public class ThreadA implements Runnable {

private boolean sometimesTrue = false;
private int[] someBigArray = new int[XXX];


private synchronized int[] getBigArray() {
    return this.someBigArray;
}

private void fireListenerDataChanged() {
    for(ThreadAListener l : listeners) 
        l.notify();
}

private synchronized void updateArray() {
    //do some stuff on the array that takes a lot of time
}

@Override
public void run() {
    while(true) {
        if(sometimesTrue) {
            updateArray();
        }
    }
}


public void doUpdate() {
    this.sometimesTrue = true;
}

}


public class ThreadB implements Runnable, ThreadAListener  {

private int[] bigDataToWorkOn;
private Thread threadA;

public ThreadB(ThreadA threadA) {
    this.threadA = threadA;
}

@Override
public void run() {
        //do my stuff with bigDataToWorkOn 
        if(sometimesTrue) {
            threadA.doUpdate();
        }
}


public void notify() {
    this.bigDataToWorkOn = threadB.getBigArray();
}      

}

My main goal was to avoid using some kind of BlockingQueue because then afaik ThreadB would wait with his work until ThreadA passes the data in the queue. The same problem would occur if I would call getBigArray in the while-loop in ThreadB because when ThreadA is currently working in updateArray, ThreadA would be locked and ThreadB would also wait for ThreadA to finish. So is this a proper approach?


Solution

  • This approach could be workable solution, except that fact, that you must mark field sometimesTrue with volatile modifier, if you don't want to have infinite loop inside your run() method of ThreadA.

    Futhermore, if you don't want your ThreadA be eating 100% of single core, you have to add some delay into loop inside its run() method:

    public void run() {
        try {
            while(true) {
                if(sometimesTrue) {
                   updateArray();
                }
                Thread.sleep(100);
            }
        } catch (InterruptedException e) {
          // ... do something with e 
        }
    }