0

This TestCode is supposed to create an stream of numbers in seconds. Collect 10 samples, and average the time which each samples comes out. I did try to use if-else, but the variable from if doesn't share with else. Please correct me if I'm wrong. I don't understand lambda just yet.

public class TestCode {

    private int eachTwoSec;

    // supposed to aList.add 10 items
    // average the time needed in between each aList.add (2 obviously)
    public void avgTimeTaken() {
        ArrayList aList = new ArrayList();
        for (int i = 0; i < 10; i++) {
            aList.add(eachTwoSec);
        }
    }

    // return a number every two seconds (endless stream of samples)
    // samples 50,52,54,56,58,60,2,4,6,8,10
    public void twoSecTime() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
            Logger.getLogger(Dummies.class.getName()).log(Level.SEVERE, null, ex);
        }

        LocalDateTime ldt = LocalDateTime.now();
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("ss");
        eachTwoSec = Integer.parseInt(ldt.format(dtf));
        System.out.println(eachTwoSec);
        twoSecTime();
    }

    public TestCode() {
        // construct
        avgTimeTaken();
        new Thread(this::twoSecTime).start();
    }

    public static void main(String[] args) {
        // just a start point
        new TestCode();
    }
}
WHISKAS
  • 3
  • 3
  • 1
    If you're using multiple threads, you *never* want to access the same variable unsynchronized. At the very least, you need to use a [synchronized block](https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html), and in your case it looks like you probably want a producer/consumer pattern with something like a [ConcurrentLinkedQueue](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html). – Silvio Mayolo May 31 '21 at 15:54
  • 1
    Your question title is misleading. When you run `avgTimeTaken()`, you just add `0`, ten times. The thread hasn't even started yet. Your question is not at all about how to average numbers in a list, it's about how to manage threads. – rzwitserloot May 31 '21 at 15:57
  • 1
    For starters: You are getting warnings about using a raw type on `ArrayList`, and you need to pay attention to them. – chrylis -cautiouslyoptimistic- May 31 '21 at 16:08
  • 1
    Never use `LocalDateTime` for tracking moments, specific points on the time line. I cannot imagine any scenario where calling `LocalDateTime.now()` is the right thing to do. Use `Instant` or `ZonedDateTime` for such work. – Basil Bourque May 31 '21 at 16:30

2 Answers2

1

The literal answer to the question "How do I average the contents in ArrayList?" for a List<Integer> is:

list.stream().mapToInt(Integer::intValue).average();

Though I suspect that's not really what you need to know given the concurrency issues in your code.

sprinter
  • 27,148
  • 6
  • 47
  • 78
0

This may help to do what you want (or give you a place from which to proceed).

  • I use a timer to take action every 2000 ms. I prefer using the Swing timer and not messing around with TimerTasks.
  • I don't just add 2 sec but grab the current nanoSecond time
  • This introduces latency errors introduced by various parts of the code and of synchronicities.
  • I add the microseconds to the ArrayList. These are in the form of delta from the most recent to the previously recorded value.
  • and when count == 10 I stop the timer and invoke the averaging method.
  • Most of the work is done on the EDT (normally a bad thing but okay for this exercise). If that were a problem, another thread could be started to handle the load.
  • I then use the original main thread to signal wait to leave the JVM. Imo, preferred over System.exit(0);

The gathered data and final average are all in microseconds.

import java.util.ArrayList;
import javax.swing.Timer;

public class TestCode {
    
    Timer timer;
    int delay = 2000; // milliseconds
    int count = 0;
    long last;
    
    ArrayList<Integer> aList = new ArrayList<>();
    Object mainThread;
    
    public void avgTimeTaken() {
        
        double sum = 0;
        for (Integer secs : aList) {
            sum += secs;
        }
        System.out.println("Avg = " + sum / aList.size());
    }
    
    public void twoSecTime() {
        long now = System.nanoTime();
        int delta = (int) (now / 1000 - last / 1000); // microseconds
        last = now;
        aList.add(delta);
        System.out.println(delta);
        count++;
        if (count == 10) {
            // stop the time
            timer.stop();
            // get the averages
            avgTimeTaken();
            // wake up the wait to exit the JVM
            // twoSecTime is run on the EDT via timer
            // so need to use mainThread
            synchronized (mainThread) {
                mainThread.notifyAll(); 
            }
        }
    }
    
    public static void main(String[] args) {
        new TestCode().start();
    }
    
    public void start() {
        mainThread = this;
        timer = new Timer(2000, (ae) -> twoSecTime());
        last = System.nanoTime(); // initialize last
        timer.start();
        synchronized (this) {
            try {
                wait(); // main thread waiting until all is done
            } catch (InterruptedException ie) {
                ie.printStackTrace();
            }
        }
    }
}
WJS
  • 36,363
  • 4
  • 24
  • 39