ActiveMQ 5.8.0 事务相关示例程序分析

ActiveMQ 5.8.0 事务相关示例程序分析

 

示例程序在版本中的位置:apache-activemq-5.8.0\example\transactions

 

1. 概述

 

该示例程序模拟了一个电脑采购的过程:零售商(Retailer)向中间商(Vendor)下订单订购电脑,中间商收到订单后,

向供应商(Supplier)订购电脑配件(存储硬件和显示器).

 

示例中用3个类分别模拟Retailer,Vendor和Supplier.

 

然后使用TransactionsDemo类同时执行Retailer,Vendor和Supplier,

因为供应商有两个,所以启动了两个Supplier线程.

 

    Retailer r = new Retailer(url, user, password);

    Vendor v = new Vendor(url, user, password);

    Supplier s1 = new Supplier("HardDrive", "StorageOrderQueue", url, user, password);

    Supplier s2 = new Supplier("Monitor", "MonitorOrderQueue", url, user, password);

 

    new Thread(r, "Retailer").start();

    new Thread(v, "Vendor").start();

    new Thread(s1, "Supplier 1").start();

    new Thread(s2, "Supplier 2").start();

 

2. Retailer

 

   Retailer没有使用事务.该类向VendorOrderQueue队列发送Map类型的订单消息.

   

   并创建了一个临时消息目的地用来接收Vendor类处理VendorOrderQueue队列中

   订单消息之后发送的反馈.

   

   发送5个订单之后,发送一个空消息来结束当前线程.

   

   当一个订单消息发送之后,Retailer类使用replyConsumer.receive();方法同步接收

   Vendor的反馈,当订单正常处理完成后,Vendor类发送反馈给Retailer,Retailer收到

   反馈后,才发送下一个订单消息.

   

3. Vendor

 

   Vendor类同步接收VendorOrderQueue队列队列中的消息,异步接收Supplier的反馈.

   Vendor接收到VendorOrderQueue队列中的订单消息之后,发送两个消息给对应的Supplier

   然后接收Supplier的反馈,当两个Supplier都正常反馈之后,再发送反馈消息给Retailer,通知

   订单处理情况.

   

   Vendor使用了事务,将从VendorOrderQueue接收消息和向两个Supplier发送消息放到一个事务中.

   只有同时正常接收了VendorOrderQueue的订单消息和向StorageOrderQueue和MonitorOrderQueue

   发送消息之后才提交事务,否则回滚事务.

   

   Vendor处理Supplier确认消息分析:

   Vendor本身实现了MessageListener接口,并将自身注册为Supplier确认消息目的地的Listener.

   confirmConsumer.setMessageListener(this);

   

   Vendor使用了一个内部类Order来作为辅助类来处理Supplier的确认消息.

   Supplier确认消息消费者confirmConsumer异步处理确认消息.

   有一点需要注意,:JMS1.1规范中规定,Session使用单一线程

   来运行所有的MessageListener,当线程在执行一个监听器时,所有其他被异步转发的消息必须等待.

   上述规范对理解Order类的处理方式有帮助.

   

   Vendor在接收到订单消息之后,会new一个Order对象,new Order(message);新建对象时,

   Order内部使用pendingOrders.put(orderNumber, this);方法保存每一个订单对象,

   pendingOrders   = new HashMap<Integer, Order>();pendingOrders根据订单编号(1-5)映射订单.

   new Order(message);后,新建Order的Status为Pending

   

   Vendor使用MessageListener处理Supplier确认消息时,也是根据订单编号获取保存在

   pendingOrders中的Order实例的.

   

   处理Supplier确认消息时,先执行下面代码:

   orderNumber = componentMessage.getInt("VendorOrderNumber");

   Order order = Order.getOrder(orderNumber);

   order.processSubOrder(componentMessage);

   asyncSession.commit(); //这里是为了确认消息已被处理(只处理了一个Supplier的确认消息).因为asyncSession创建方式为

   //asyncSession = asyncconnection.createSession(true, Session.SESSION_TRANSACTED);

   //使用了Session.SESSION_TRANSACTED

   

   其中processSubOrder,是真正处理Supplier确认消息的.参数componentMessage是Supplier发送的确认消息.

   Order中使用monitor和storage来保存两个Supplier的确认消息,当这两个字段不为null时,表示订单处理完了.

   然后将Oreder的Status状态变成Fulfilled(如果处理错误,则Oreder的Status变成Canceled).

   

   回到MessageListener的OnMessage中的如下代码:

   

      if (!"Pending".equals(order.getStatus()))

      {

        System.out.println("Vendor: Completed processing for order " + orderNumber);

 

        MessageProducer replyProducer = asyncSession.createProducer(order.getMessage().getJMSReplyTo());

        MapMessage replyMessage = asyncSession.createMapMessage();

        if ("Fulfilled".equals(order.getStatus()))

        {

          replyMessage.setBoolean("OrderAccepted", true);

          System.out.println("Vendor: sent " + order.quantity + " computer(s)");

        }

        else

        {

          replyMessage.setBoolean("OrderAccepted", false);

          System.out.println("Vendor: unable to send " + order.quantity + " computer(s)");

        }

        replyProducer.send(replyMessage);

        asyncSession.commit();

        System.out.println("Vender: committed transaction 2");

      }

      

   当Order的Status不是Pending时,一个订单的两个Supplier确认消息处理完毕了.然后发送订单确认消息给Retailer,

   因为使用了事务,所以调用asyncSession.commit();提交发送消息.

   

   这里使用了事务,但是处理Supplier的确认消息时,没有回退(rollback).

   

4. Supplier

   Supplier类使用事务,同步接收Vendor的消息,处理完之后,发送确认消息给Vendor.

   

   

5.程序如何结束

 

  首先Retailer发送完5个订单消息之后,会一个空消息(非Map)消息给Vendor,表示结束程序.

  // Send a non-MapMessage to signal the end

  producer.send(session.createMessage());

  

  Vender收到空消息之后,也会发送两个空消息给Supplier,并调用break结束线程调用.

  else// if (inMessage instanceof MapMessage)

  {

    // end of stream

    Message outMessage = session.createMessage();

    outMessage.setJMSReplyTo(vendorConfirmQueue);

    monitorProducer.send(outMessage);

    storageProducer.send(outMessage);

    session.commit();

    break;

  }

  

  Supplier收到空消息之后,发送空消息作为确认消息,然后使用break结束线程调用.

  else

  {

    // End of Stream

    producer.send(session.createMessage());

    session.commit();

    producer.close();

    break;

  }

  

  Vendor在发送了5个订单消息之后,发送一个空消息,然后将线程wait(),并监控numSuppliers,

  当numSuppliers>0时表示还有空的Supplier确认消息需要处理.

  

  Vendor的MessageListener收到空的Supplier确认消息之后,先将numSuppliers--,然后通知Vendor继续Run.

  收到第二个Supplier确认消息之后,Vendor继续Run,此时不用在wait()了.

  

  然后,即可执行

  synchronized (supplierLock)

  {

    while (numSuppliers > 0)

    {

      try

      {

        supplierLock.wait();

      }

      catch (InterruptedException e)

      {

        e.printStackTrace();

      }

    }

  }

  

  之后的代码:

  connection.close();

  asyncconnection.close();

  

  这里使用同步,是为了保证MessageListener处理完毕之后才可以调用下面的代码来关闭connection和asyncconnection(session)

  connection.close();

  asyncconnection.close();

  

P.S. JMS1.1规范中关于事务的描述:

当事务提交时,输入原子单元被确认,输出原子单元被发送。

如果事务回滚,则它生产的消息被销毁,它消费的消息被自动恢复。

  

 源码:

package com.jackyin.testamqtran;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
 * applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TemporaryQueue;

/**
 * The Retailer orders computers from the Vendor by sending a message via
 * the VendorOrderQueue. It then syncronously receives the reponse message
 * and reports if the order was successful or not.
 */
public class Retailer implements Runnable
{
  private String url;
  private String user;
  private String password;

  public Retailer(String url, String user, String password)
  {
    this.url = url;
    this.user = user;
    this.password = password;
  }

  public void run()
  {
    ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, url);
    try
    {
      Connection connection = connectionFactory.createConnection();

      // The Retailer's session is non-trasacted.
      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
      Destination vendorOrderQueue = session.createQueue("VendorOrderQueue");
      TemporaryQueue retailerConfirmQueue = session.createTemporaryQueue();

      MessageProducer producer = session.createProducer(vendorOrderQueue);
      MessageConsumer replyConsumer = session.createConsumer(retailerConfirmQueue);

      connection.start();

      for (int i = 0; i < 5; i++)
      {
        //System.out.println("预定: " + i);
        
        MapMessage message = session.createMapMessage();
        message.setString("Item", "Computer(s)");
        int quantity = (int) (Math.random() * 4) + 1;
        message.setInt("Quantity", quantity);
        message.setJMSReplyTo(retailerConfirmQueue);
        producer.send(message);
        System.out.println("Retailer: Ordered " + quantity + " computers.");

        MapMessage reply = (MapMessage) replyConsumer.receive();
        if (reply.getBoolean("OrderAccepted"))
        {
          System.out.println("Retailer: Order Filled");
        }
        else
        {
          System.out.println("Retailer: Order Not Filled");
        }
      }

      // Send a non-MapMessage to signal the end
      producer.send(session.createMessage());

      replyConsumer.close();
      connection.close();

    }
    catch (JMSException e)
    {
      e.printStackTrace();
    }
  }

  public static void main(String[] args)
  {
    String url = "tcp://localhost:61616";
    String user = null;
    String password = null;

    if (args.length >= 1)
    {
      url = args[0];
    }

    if (args.length >= 2)
    {
      user = args[1];
    }

    if (args.length >= 3)
    {
      password = args[2];
    }

    Retailer r = new Retailer(url, user, password);

    new Thread(r, "Retailer").start();
  }
}

 

   

package com.jackyin.testamqtran;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
 * applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TemporaryQueue;

import org.apache.activemq.ActiveMQConnectionFactory;

/**
 * The Vendor synchronously, and in a single transaction, receives the
 * order from VendorOrderQueue and sends messages to the two Suppliers via
 * MonitorOrderQueue and StorageOrderQueue.
 * The responses are received asynchronously; when both responses come
 * back, the order confirmation message is sent back to the Retailer.
 */
public class Vendor implements Runnable, MessageListener
{
  private String  url;
  private String  user;
  private String  password;
  private Session asyncSession;
  private int     numSuppliers = 2;
  private Object  supplierLock = new Object();

  public Vendor(String url, String user, String password)
  {
    this.url = url;
    this.user = user;
    this.password = password;
  }

  public void run()
  {
    ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, url);
    Session session = null;
    Destination orderQueue;
    Destination monitorOrderQueue;
    Destination storageOrderQueue;
    TemporaryQueue vendorConfirmQueue;
    MessageConsumer orderConsumer = null;
    MessageProducer monitorProducer = null;
    MessageProducer storageProducer = null;

    try
    {
      Connection connection = connectionFactory.createConnection();

      session = connection.createSession(true, Session.SESSION_TRANSACTED);
      orderQueue = session.createQueue("VendorOrderQueue");
      monitorOrderQueue = session.createQueue("MonitorOrderQueue");
      storageOrderQueue = session.createQueue("StorageOrderQueue");

      orderConsumer = session.createConsumer(orderQueue);
      monitorProducer = session.createProducer(monitorOrderQueue);
      storageProducer = session.createProducer(storageOrderQueue);

      Connection asyncconnection = connectionFactory.createConnection();
      asyncSession = asyncconnection.createSession(true, Session.SESSION_TRANSACTED);

      vendorConfirmQueue = asyncSession.createTemporaryQueue();
      MessageConsumer confirmConsumer = asyncSession.createConsumer(vendorConfirmQueue);
      confirmConsumer.setMessageListener(this);

      asyncconnection.start();

      connection.start();

      while (true)
      {
        Order order = null;
        try
        {
          Message inMessage = orderConsumer.receive();
          MapMessage message;
          if (inMessage instanceof MapMessage)
          {
            message = (MapMessage) inMessage;

          }
          else
          {
            // end of stream
            Message outMessage = session.createMessage();
            outMessage.setJMSReplyTo(vendorConfirmQueue);
            monitorProducer.send(outMessage);
            storageProducer.send(outMessage);
            session.commit();
            break;
          }

          // Randomly throw an exception in here to simulate a Database error
          // and trigger a rollback of the transaction
          if (new Random().nextInt(3) == 0)
          {
            //throw new JMSException("Simulated Database Error.");
          }

          order = new Order(message);

          MapMessage orderMessage = session.createMapMessage();
          orderMessage.setJMSReplyTo(vendorConfirmQueue);
          orderMessage.setInt("VendorOrderNumber", order.getOrderNumber());
          int quantity = message.getInt("Quantity");
          System.out.println("Vendor: Retailer ordered " + quantity + " " + message.getString("Item"));

          orderMessage.setInt("Quantity", quantity);
          orderMessage.setString("Item", "Monitor");
          monitorProducer.send(orderMessage);
          System.out.println("Vendor: ordered " + quantity + " Monitor(s)");

          orderMessage.setString("Item", "HardDrive");
          storageProducer.send(orderMessage);
          System.out.println("Vendor: ordered " + quantity + " Hard Drive(s)");

          session.commit();
          System.out.println("Vendor: Comitted Transaction 1");

        }
        catch (JMSException e)
        {
          System.out.println("Vendor: JMSException Occured: " + e.getMessage());
          e.printStackTrace();
          session.rollback();
          System.out.println("Vendor: Rolled Back Transaction.");
        }
      }

      synchronized (supplierLock)
      {
        while (numSuppliers > 0)
        {
          try
          {
            //System.out.println("wait()之前...");
            supplierLock.wait();
            //System.out.println("wait()之后...");
          }
          catch (InterruptedException e)
          {
            e.printStackTrace();
          }
        }
      }

      connection.close();
      asyncconnection.close();

    }
    catch (JMSException e)
    {
      e.printStackTrace();
    }

  }

  public void onMessage(Message message)
  {
    if (!(message instanceof MapMessage))
    {
      synchronized (supplierLock)
      {
        numSuppliers--;
        supplierLock.notifyAll();
        System.out.println("准备唤醒...");
        
      }
      try
      {
        asyncSession.commit();
        return;
      }
      catch (JMSException e)
      {
        e.printStackTrace();
      }
    }

    int orderNumber = -1;
    try
    {
      MapMessage componentMessage = (MapMessage) message;

      orderNumber = componentMessage.getInt("VendorOrderNumber");
      Order order = Order.getOrder(orderNumber);
      order.processSubOrder(componentMessage);
      asyncSession.commit();

      if (!"Pending".equals(order.getStatus()))
      {
        System.out.println("Vendor: Completed processing for order " + orderNumber);

        MessageProducer replyProducer = asyncSession.createProducer(order.getMessage().getJMSReplyTo());
        MapMessage replyMessage = asyncSession.createMapMessage();
        if ("Fulfilled".equals(order.getStatus()))
        {
          replyMessage.setBoolean("OrderAccepted", true);
          System.out.println("Vendor: sent " + order.quantity + " computer(s)");
        }
        else
        {
          replyMessage.setBoolean("OrderAccepted", false);
          System.out.println("Vendor: unable to send " + order.quantity + " computer(s)");
        }
        replyProducer.send(replyMessage);
        asyncSession.commit();
        System.out.println("Vender: committed transaction 2");
      }
    }
    catch (JMSException e)
    {
      e.printStackTrace();
    }
  }

  public static class Order
  {
    private static Map<Integer, Order> pendingOrders   = new HashMap<Integer, Order>();
    private static int                 nextOrderNumber = 1;

    private int                        orderNumber;
    private int                        quantity;
    private MapMessage                 monitor         = null;
    private MapMessage                 storage         = null;
    private MapMessage                 message;
    private String                     status;

    public Order(MapMessage message)
    {
      this.orderNumber = nextOrderNumber++;
      this.message = message;
      try
      {
        this.quantity = message.getInt("Quantity");
      }
      catch (JMSException e)
      {
        e.printStackTrace();
        this.quantity = 0;
      }
      status = "Pending";
      pendingOrders.put(orderNumber, this);
    }

    public Object getStatus()
    {
      return status;
    }

    public int getOrderNumber()
    {
      return orderNumber;
    }

    public static int getOutstandingOrders()
    {
      return pendingOrders.size();
    }

    public static Order getOrder(int number)
    {
      return pendingOrders.get(number);
    }

    public MapMessage getMessage()
    {
      return message;
    }

    public void processSubOrder(MapMessage message)
    {
      String itemName = null;
      try
      {
        itemName = message.getString("Item");
      }
      catch (JMSException e)
      {
        e.printStackTrace();
      }

      if ("Monitor".equals(itemName))
      {
        monitor = message;
      }
      else if ("HardDrive".equals(itemName))
      {
        storage = message;
      }

      if (null != monitor && null != storage)
      {
        // Received both messages
        try
        {
          if (quantity > monitor.getInt("Quantity"))
          {
            status = "Cancelled";
          }
          else if (quantity > storage.getInt("Quantity"))
          {
            status = "Cancelled";
          }
          else
          {
            status = "Fulfilled";
          }
        }
        catch (JMSException e)
        {
          e.printStackTrace();
          status = "Cancelled";
        }
      }
    }
  }

  public static void main(String[] args)
  {
    String url = "tcp://localhost:61616";
    String user = null;
    String password = null;

    if (args.length >= 1)
    {
      url = args[0];
    }

    if (args.length >= 2)
    {
      user = args[1];
    }

    if (args.length >= 3)
    {
      password = args[2];
    }

    Vendor v = new Vendor(url, user, password);

    new Thread(v, "Vendor").start();
  }
}

 

   

package com.jackyin.testamqtran;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
 * applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
import java.util.Random;

import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;

import org.apache.activemq.ActiveMQConnectionFactory;

/**
 * The Supplier synchronously receives the order from the Vendor and
 * randomly responds with either the number ordered, or some lower
 * quantity. 
 */
public class Supplier implements Runnable
{
  private String       url;
  private String       user;
  private String       password;
  private final String ITEM;
  private final String QUEUE;

  public Supplier(String item, String queue, String url, String user, String password)
  {
    this.url = url;
    this.user = user;
    this.password = password;
    this.ITEM = item;
    this.QUEUE = queue;
  }

  public void run()
  {
    ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, url);
    Session session = null;
    Destination orderQueue;
    try
    {
      Connection connection = connectionFactory.createConnection();

      session = connection.createSession(true, Session.SESSION_TRANSACTED);
      orderQueue = session.createQueue(QUEUE);
      MessageConsumer consumer = session.createConsumer(orderQueue);

      connection.start();

      while (true)
      {
        Message message = consumer.receive();
        MessageProducer producer = session.createProducer(message.getJMSReplyTo());
        MapMessage orderMessage;
        if (message instanceof MapMessage)
        {
          orderMessage = (MapMessage) message;
        }
        else
        {
          // End of Stream
          producer.send(session.createMessage());
          session.commit();
          producer.close();
          break;
        }

        int quantity = orderMessage.getInt("Quantity");
        System.out.println(ITEM + " Supplier: Vendor ordered " + quantity + " " + orderMessage.getString("Item"));

        MapMessage outMessage = session.createMapMessage();
        outMessage.setInt("VendorOrderNumber", orderMessage.getInt("VendorOrderNumber"));
        outMessage.setString("Item", ITEM);

        quantity = Math
            .min(orderMessage.getInt("Quantity"), new Random().nextInt(orderMessage.getInt("Quantity") * 10));
        outMessage.setInt("Quantity", quantity);

        producer.send(outMessage);
        System.out.println(ITEM + " Supplier: Sent " + quantity + " " + ITEM + "(s)");
        session.commit();
        System.out.println(ITEM + " Supplier: committed transaction");
        producer.close();
      }
      connection.close();
    }
    catch (JMSException e)
    {
      e.printStackTrace();
    }
  }

  public static void main(String[] args)
  {
    String url = "tcp://localhost:61616";
    String user = null;
    String password = null;
    String item = "HardDrive";

    if (args.length >= 1)
    {
      item = args[0];
    }
    String queue;
    if ("HardDrive".equals(item))
    {
      queue = "StorageOrderQueue";
    }
    else if ("Monitor".equals(item))
    {
      queue = "MonitorOrderQueue";
    }
    else
    {
      throw new IllegalArgumentException("Item must be either HardDrive or Monitor");
    }

    if (args.length >= 2)
    {
      url = args[1];
    }

    if (args.length >= 3)
    {
      user = args[2];
    }

    if (args.length >= 4)
    {
      password = args[3];
    }

    Supplier s = new Supplier(item, queue, url, user, password);

    new Thread(s, "Supplier " + item).start();
  }
}

 

package com.jackyin.testamqtran;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
 * applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
public class TransactionsDemo
{

  public static void main(String[] args)
  {
    String url = "tcp://localhost:61616";
    String user = null;
    String password = null;

    if (args.length >= 1)
    {
      url = args[0];
    }

    if (args.length >= 2)
    {
      user = args[1];
    }

    if (args.length >= 3)
    {
      password = args[2];
    }

    Retailer r = new Retailer(url, user, password);
    Vendor v = new Vendor(url, user, password);
    Supplier s1 = new Supplier("HardDrive", "StorageOrderQueue", url, user, password);
    Supplier s2 = new Supplier("Monitor", "MonitorOrderQueue", url, user, password);

    new Thread(r, "Retailer").start();
    new Thread(v, "Vendor").start();
    new Thread(s1, "Supplier 1").start();
    new Thread(s2, "Supplier 2").start();
  }

}

 

   

   

   

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值