How to avoid a loop in this code

I send prices to clients (10000+), but below the code has a loop that causes delays in the process for clients awaiting calculation.

PriceVisibleForCustomer = Price + CustomerMargin

Price - changes every 300 ms - sent from a central store that is not related to the customer’s instance

CustomerMargn - a certain amount of plus or minus resulting from an agreement with a client / segment / administrator, etc. It does not change during the http client session, I can save it in memory

Client - he takes part in this process after entering the system, he should see rapidly changing prices for 8 products.

Maybe I need some more technology? I have Spring 3/4, Java, Weblogic, and I could even create a separate webapp for this task to provide estimated prices.

I was thinking of threads in Java, but 10,000+ clients would mean too many threads, right? How to change this code? Maybe I need to change the architecture, but how?

/** * Sends prices to customer. This method is called very often (300ms) as prices are changing in real time. * Customer should see prices also each 300ms * @param productId - id of a product that prices will be calculated * @param productIdToPriceMap * @param customerIdToMarginMap - this map is changed every time customer logs in or logs out */ private static void sendPricesToCustomers(Long productId, Map<Long, BigDecimal> productIdToPriceMap, Map<Long, BigDecimal> customerIdToMarginMap) { //This loop is blocking last customer from receiving price until all other customers wil have theri prices calculated. I could create threads, 10000+ customers will be logged in, I cant create so much threads... can I? for (Long customerId: customerIdToMarginMap.keySet()){ BigDecimal customerMargin = customerIdToMarginMap.get(customerId); BigDecimal priceResult = productIdToPriceMap.get(productId).add(customerMargin); //send priceResult to websocket } } 
+6
source share
2 answers

Here is a simple example of a Listener template, I'm not sure if this approach will work for you, but it just throws out some ideas ...

 import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Vector; import javax.swing.Timer; public class Demo { public static Product[] PRODUCTS = new Product[]{ new Product("Computer", 400), new Product("Desk", 800), new Product("Chair", 70), new Product("Printer", 300), new Product("Television", 200) }; public static void main(String[] args) throws InterruptedException { Customer john = new Customer("John", 3); john.addProduct(PRODUCTS[1]); john.addProduct(PRODUCTS[2]); john.addProduct(PRODUCTS[3]); Customer mary = new Customer("Mary", 2); mary.addProduct(PRODUCTS[1]); mary.addProduct(PRODUCTS[2]); mary.addProduct(PRODUCTS[4]); Thread.sleep(10000); System.exit(0); } } interface IPriceListener { public void priceChanged(Product product, int price); } class Customer implements IPriceListener { String _name; int _margin; Vector<Product> _products = new Vector<Product>(); public Customer(String name, int margin){ _name = name; _margin = margin; } public void addProduct(Product product){ _products.add(product); product.addListener(this); } public void priceChanged(Product product, int price) { System.out.println("[" + _name + "][" + _products.get(_products.indexOf(product)).getName() + "][" + price + "][" + (price + _margin) + "]"); } } class Product implements ActionListener { private int _startingPrice; private int _currentPrice; private String _name; private Timer _timer; private Vector<IPriceListener> _listeners = new Vector<IPriceListener>(); public Product(String name, int price) { _name = name; _startingPrice = _currentPrice = price; _timer = new Timer(300, this); _timer.start(); } public void addListener(IPriceListener listener) { _listeners.add(listener); } public void removeListener(IPriceListener listener){ _listeners.remove(listener); } private void notifyListeners() { for(IPriceListener listener : _listeners){ listener.priceChanged(this, getCurrentPrice()); } } public void actionPerformed(ActionEvent e) { _currentPrice = _startingPrice + (int)(Math.random() * (5 - (-5))) + (-5); notifyListeners(); } public final String getName() { return _name; } private synchronized final int getCurrentPrice() { return _currentPrice; } } 
+1
source

One way to deal with this is to create one thread, the task of which is to consume price results from the queue and send them via websocket (I assume that you have only one website). Then your loop will push priceResults into the queue every 300 ms without blocking the websocket stream. See ConcurrentLinkedQueue javadoc .

Edit: To avoid the delay between completing the current cycle through customerIdToMarginMap and starting the next update cycle, do the following:

  • Keep the concept of the queue and create a fixed thread pool where each thread pulls the next line customerId / productIdToPriceMap / customerIdToMarginMap from the queue. If you have four streams and 10,000 records, each stream should only process 2500 records, thereby starting from the next 300 second data entry 4 times earlier than your current implementation. Increase the number of threads required for performance.

  • Keep my original concept of the queue, but change the way you get price updates. The reason you need to get hung up on is because you get price updates for each customer at the same time. If you can instead, for example, create a stream listener for a group of customers that receives a customerIdToMarginMap containing only the customerId that it is intended to process, the iteration time will be significantly reduced.

0
source

All Articles