如何避免此代码中的循环

时间:2015-07-18 14:57:34

标签: java spring spring-messaging

我向客户发送价格(10000+)但是代码下面有循环导致客户等待计算的过程延迟。

PriceVisibleForCustomer =价格+ CustomerMargin

价格 - 每隔300毫秒更换一次 - 从中​​央商店发送,与客户实例无关

CustomerMargn - 由客户协议/分部/管理员决定等产生的一些正负金额。在客户http会话期间没有变化,我可以将其保留在内存中

客户 - 他登录后参与了这个过程,他应该看到8种产品价格的快速变化。

也许我需要更多技术?我有Spring 3/4,Java,Weblogic,我可以为此任务创建甚至单独的webapp来提供计算价格。

我考虑过Java中的线程,但是10000多个客户意味着太多的线程不是吗?如何更改此代码?也许我应该改变架构,但是如何?

/**
     * 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
        }

    }

2 个答案:

答案 0 :(得分:1)

这是一个监听器模式的简单示例,我不确定这种方法是否适合您,但只是抛出一些想法......

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 :(得分:0)

解决这个问题的一种方法是创建一个单独的线程,其作用是从队列中消耗priceResults并将它们发送到websocket(我假设你只有一个websocket)。然后,您的循环将每300毫秒将priceResults推送到队列,而不会阻止websocket线程。请参阅ConcurrentLinkedQueue javadoc

修改 为了避免在完成当前循环到_JAVA_OPTION之间的延迟并开始循环下一次更新,这里有一些选项:

  1. 保持队列概念并创建一个固定的线程池,其中每个线程从队列中提取下一个customerIdToMarginMap / customerId / productIdToPriceMap。如果您有四个线程和10,000个记录,则每个线程只需处理2,500条记录,从而比当前实现早4次开始下一次300ms数据。在您发现性能所需的时候增加线程数。

  2. 保留原始队列概念,但更改收到价格更新的方式。您需要循环的原因是因为您同时获得每个客户的定价更新。如果你可以改为为一组客户创建一个线程监听器,这些客户收到的customerIdToMarginMap只包含它要处理的customerIdToMarginMap,迭代时间将会大大减少。