6

我正在向客户发送价格(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
        }

    }
4

2 回答 2

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;
  }
}
于 2015-07-18T16:57:58.750 回答
0

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

编辑: 为了避免完成当前循环customerIdToMarginMap和开始循环下一次更新之间的延迟,这里有一些选项:

  1. 保持队列的概念,创建一个固定的线程池,每个线程将下一个customerId//拉出队列。如果您有 4 个线程和 10,000 条记录,则每个线程只需处理 2,500 条记录,因此在接下来的 300 毫秒数据推送中比您当前的实现提前 4 倍开始。在您认为性能需要时增加线程数。productIdToPriceMapcustomerIdToMarginMap

  2. 保留我最初的队列概念,但改变您接收价格更新的方式。您需要循环的原因是因为您同时为每个客户获取定价更新。如果您可以改为为一组客户创建一个线程侦听器,该侦听器customerIdToMarginMap仅接收包含customerId它要处理的 s ,则迭代时间将显着减少。

于 2015-07-18T15:46:36.457 回答