资讯专栏INFORMATION COLUMN

基于LinkedBlockingQueue实现股票交易系统

30e8336b8229 / 3217人阅读

摘要:与基于数组的队列相同,重载的构造函数可以接受集合指定的初始值。这种队列比基于数组阻塞队列具有更高的吞吐量。创建个交易者实例,将自己出售的订单放入队列中,每个出售订单都将会有随机的交易量。要使用基于优先级的队列,需要提供适当的比较器。

阻塞队列

在阻塞队列的帮助下,许多同步问题都可以被公式化。阻塞队列是队列,当线程试图对空队列进行出列操作,或试图向满的队列中插入条目时,队列就会阻塞。直到其他线程向队列中放入数据时才可以移除,同样,直到其他线程从队列中移除条目之后才可以加入。通过使用 轮询或等待-通知机制可以实现阻塞队列。就轮询机制来说,读线程周期性的调用队列的get方法,直到队列的消息变为可用。至于等待-通知机制,读线程仅仅是等待队列对象,队列对象会在有条目时通知线程。

阻塞队列的特征

阻塞队列的典型特征可以概括如下:

阻塞队列提供了方法来向其中添加条目。这些方法的调用都是阻塞调用的,其中条目的插入必须等待,直到队列的空间变为可用。

队列提供了方法来从中删除条目,对这些方法的调用同样是阻塞调用的。调用者会等待条目被放入空队列

add和remove方法可以选择性地为它们的等待操作提供超时并可能被中断

put和take操作在多带带的线程中实现,从而在两种类型的操作之间提供了良好的绝缘性

不能像阻塞队列中插入null元素

阻塞队列可能受容量的限制

阻塞队列的实现是线程安全的,然而批量操作,比如addAll,没有必要一定原子地执行,

阻塞队列在本质上不支持“关闭”或“停止”操作,这表示没有更多的条目可添加

LinkedBlockingQueue

LinkedBlockingQueue是通过将阻塞队列的最大容量变为可变,进而扩展了数据阻塞队列的概念。你仍然可以在指定容量已禁止过度扩容。如果不指定容量,默认值是最大的整数值。没有容量限制是由好处的,因为如果先飞着晚于预订时间选取条目,生产者无需等待。与基于数组的队列相同,重载的构造函数可以接受集合指定的初始值。这种队列比基于数组阻塞队列具有更高的吞吐量。但同时也有较少的可预见性。除了移除操作在线性时间运行之外,队列的大多数操作都是在常数时间内运行的。

PriorityBlockingQueue

PriorityBlockingQueue是无界队列,可以决定元素的优先顺序,优先级可以由元素的自然顺序或你提供的比较器来确定。依照优先级队列的顺序,视图插入不可比较的对象会导致ClassCastException异常。如果系统资源耗尽,虽然是无界队列,添加操作也会失败,

股票交易系统
package com.guo.chap18;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Created by guo on 17/2/2018.
 * 基于阻塞队列的股票交易服务器
 * 需求:
 *      1、允许交易者往队列中添加出售订单,也可以获取待办的订单
 *      2、在任何给定的时间,如果队列已满,交易者就不得不等待某个位置变为空
 *      3、购买者必须等待,直到队列中有出售订单可用。
 *      4、为了简化情形,假设买方总是必须购买全额数量的可供出售的股票,不可以部分购买。
 */
public class StockExchange {

    public static void main(String[] args) {
        System.out.printf("Hit Enter to terminate %n%n");
        //1、创建LinkedBlockingQueue实例,因为是无限容量,所以交易者可以把任何数量的订单放入队列中,
        //   如果使用ArrayBlockingQueue,那么将会限制每只股票拥有有限次数的交易。
        BlockingQueue orderQueue = new LinkedBlockingQueue<>();
        //2、创建Seller卖家实例,Seller是Runnable的实现类。
        Seller seller = new Seller(orderQueue);
        //3、创建100个交易者实例,将自己出售的订单放入队列中,每个出售订单都将会有随机的交易量。
        Thread[] sellerThread = new Thread[100];
        for (int i = 0; i < 100; i++) {
             sellerThread[i] = new Thread(seller);
             sellerThread[i].start();
        }
        //4、创建100个买家实例,选取待售的订单
        Buyer buyer = new Buyer(orderQueue);
        Thread[] buyserThread = new Thread[100];
        for (int i = 0; i < 100; i++) {
            buyserThread[i] = new Thread(buyer);
            buyserThread[i].start();
        }
        try {
            //5、一旦创建生产者和消费者线程,他们会永远保持运行,将订单放入队列以及从队列中获取订单
            //   根据给定时间的负载情况,定期自我阻塞,终止应用程序的方法是用户在键盘上按下Enter键。
            while (System.in.read() != "
");
        } catch (IOException e) {
            e.printStackTrace();
        }
        //6、main函数会中断所有正在运行的生产者和消费者线程,要求它们中指并退出
        System.out.println("Terminating");
        for (Thread t : sellerThread) {
            t.interrupt();
        }
        for (Thread t : buyserThread) {
            t.interrupt();
        }

    }
}
卖家和买家
/**
 * 卖家
 * Seller类实现了Runnable接口并提供了以OrderQueue作为参数的构造函数
 */
class  Seller implements Runnable {
    private BlockingQueue orderQueue;
    private boolean shutdownRequest = false;
    private static int id;
    public Seller(BlockingQueue orderQueue) {
        this.orderQueue = orderQueue;
    }
    @Override
    public void run() {
        while (shutdownRequest == false) {
            //1、在每一次迭代中,为每一次的交易量生产一个随机数
            Integer quantity = (int) (Math.random() * 100);
            try {
                //2、调用put方法,将订单放入队列中,这是阻塞调用,只有在队列容量有限的情况下,
                //    线程才需要等待队列中有出现空的位置
                orderQueue.put(quantity);
                //3、为了方便用户,在控制台打印销售订单的详细信息,以及用于放置销售订单的线程详细信息
                System.out.println("Sell order by" + Thread.currentThread().getName() + ": " + quantity);
            } catch (InterruptedException e) {
                //4、run方法将无限期的运行,定期的向队列中提交订单,通过调用interrupt方法,这个线程可以被另外一个线程中断。
                //   interrupt方法产生的InterruptException异常简单的将shutdownRequest标志设置为true,将导致run方法无限循环终止
                shutdownRequest = true;
            }
        }
    }
}

/**
 *  买家
 *  Buyer类实现了Runnable接口并提供了以OrderQueue作为参数的构造函数
 */
class Buyer implements Runnable{
    private BlockingQueue orderQueue;
    private boolean shutdownRequest = false;
    public Buyer(BlockingQueue orderQueue) {
        this.orderQueue = orderQueue;
    }
    @Override
    public void run() {
        while (shutdownRequest == false) {
            try {
                //1、run方法通过调用take方法,从队列的头部取出待办的交易,
                //   如果队列中没有可用的订单,take方法将阻塞,
                Integer quantity = ((Integer) orderQueue.take());
                //2、为了方便,打印订单和线程的详细信息
                System.out.println("Buy order by " + Thread.currentThread().getName() + ": " + quantity);
            } catch (InterruptedException e) {
                shutdownRequest = true;
            }
        }
    }
}
输出
...
Buy order by Thread-134: 48
Buy order by Thread-134: 83
Buy order by Thread-134: 2
Buy order by Thread-134: 52
Sell order byThread-86: 90
Sell order byThread-86: 19
Sell order byThread-86: 64
Sell order byThread-86: 83
Sell order byThread-86: 27
Buy order by Thread-163: 94
Buy order by Thread-163: 74
...

当在键盘上按下Enter键使,程序终止

在这个程序中,如果没有使用阻塞队列,访问非同步队列中放置的交易时会发生竞争,每个人都会尝试抢得低于当前市场价格出售的股票,多个交易者会选取统一订单,交易之间会很混乱,由于阻塞队列 确保了同步地访问队列,因此交易的完整性绝不会 受到损害。

在这个例子中使用了LinkedBlockingQueue,气死也可以基于优先级的队列,这样会自动按照交易的买价和卖价对交易进行排列,具有最好买价和最低卖价的订单总是排在队列的头部。要使用基于优先级的队列,需要提供适当的比较器。

说明

1、GitHub代码欢迎star。你们轻轻的一点,对我鼓励特大。

2、个人认为学习语言最好的方式就是模仿思考别人为什么这么写。结合栗子效果更好,也能记住知识点

3、只因为自己知识欠缺,语言组织能力不行,所以只能以这样方式记录。感觉效果很好。

4、本文基于《Java 7 编程高级进阶》所写,写的非常不错,建议大家去看看

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68509.html

相关文章

  • Python量化交易基础讲堂——管理概率==理性交易

    摘要:那么我们改变概率这个因子,将它放大到,我们邀请个人参与局看下效果看来结果还不错,只要增加盈利的概率,就可以在市场中获得收益,这就是量化交易的魅力管理概率理性交易。 在《Python实战-构建基于股票的量化交易系统》小册子中,我们以股票为交易标的讲解量化交易的学习,主要原因是股票的风险和收益介于期货和基金之间。期货一方面加了杠杆,另一方面走势变化非常迅速,稍有不慎有可能血本无归,这不太适...

    AWang 评论0 收藏0
  • 从理想到现实, 你不知道的区块链

    摘要:简而言之,区块链说的是由区块用某种方式组织起来的链条。在本文中,我们说的区块链技术实际上是一种分布式数据库技术。事实上,当使用基于区块链的系统时,人们对中心机构的信任转而被对数学的信任所取代。因而,基于区块链的系统是安全的。 区块链是什么?我们来看一下区块链在维基百科上被大家公认的官方定义: 一个区块链是一个基于比特币协议的不需要许可的分布式数据库,它维护了一个持续增长的不可被篡改和修...

    seasonley 评论0 收藏0
  • 金融套利策略:理解统计套利的工作原理

    摘要:后一种方法被称之为多因子统计套利模型。套利套利可以被称为交叉资产套利的一种形式,它可以识别的价值与其相关资产之间的差异。目前,统计套利策略已经成为了对冲基金和投资银行的主要力量。 作者:chen_h微信号 & QQ:862251340微信公众号:coderpai简书地址:https://www.jianshu.com/p/ea2... 1. 什么是定量交易 定量交易是通过统计技术(或...

    whataa 评论0 收藏0
  • 说说股票配资系统中实盘交易接口的开发

    摘要:做股票配资系统难免会用到交易接口,好用的能用的接口也少。券商那边也不提供,那索性自己开发股票配资实盘交易接口了。 做股票配资系统难免会用到交易接口,好用的能用的接口也少。券商那边也不提供,那索性自己开发股票配资实盘交易接口了。经过多次尝试,总算搞出来了,实时交易接口可以获取用户数据,实时对接,账户信息,委托买入卖出,支持多家券商。 种类4(可撤单)返回 {data1: { 委托类别:...

    leoperfect 评论0 收藏0

发表评论

0条评论

30e8336b8229

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<