b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

Java-BlockingQueue接口的五个主要实现类的使用场景

电脑杂谈  发布时间:2020-07-01 04:05:07  来源:网络整理

java的queue_java queue的实现类_java queue 实现类

Queue是一种常见的数据结构,Java自然也具有这种数据结构,即Queue(继承的Collection,因此我们将队列归因于collection的范围). 阻塞队列BlockingQueue(继承的队列)是队列中具有阻塞线程功能的特殊队列.

BlockingQueue是我们所说的阻塞队列. 它的实现基于ReentrantLock. 通常,当我们谈论阻塞队列时,它将与生产者/消费者模型(这是最常用的方案)和一般的非阻塞相关联. 队列之间的区别在于,无需在生产者/消费者模型中实现额外的线程同步和唤醒.

标题涉及五个主要的实现类,但是该接口实际上具有七个实现类. 它们之间的区别主要体现在存储结构或元素的操作上,如下所示:

ArrayBlockingQueue: 由数组结构组成的有界阻塞队列.

LinkedBlockingQueue: 由链表结构组成的有界阻塞队列.

PriorityBlockingQueue: 支持优先级的无限制阻塞队列.

DelayQueue: 使用优先级队列实现的无限制阻塞队列.

SynchronousQueue: 不存储元素的阻塞队列.

LinkedTransferQueue: 由链表结构组成的无限阻塞队列.

java的queue_java queue 实现类_java queue的实现类

LinkedBlockingDeque: 由链表结构组成的双向阻止队列.

今天,我将主要讨论前五个类别的使用场景. 对于最后两类,作者没有在实际项目中使用它,因此我将不对其进行分析.

功能: 基于阵列的实现,队列容量是固定的. 存储/检索数据的操作共享一个锁(默认为不公平锁定),并且不可能真正实现并行执行存储/检索操作.

分析: 由于阵列是基于固定容量的,因此要获得很高的内存占用率并不容易,但是如果容量太小并且获取数据的速度比存储数据的速度慢java queue的实现类,也会导致许多线程进入该块(您也可以使用offer()方法实现非阻塞线程). 另外,由于访问共享锁,因此对并发性和吞吐量有很高的要求,因此不建议使用ArrayBlockingQueue.

使用场景: 在上述情况下,作者认为其使用场景应放在项目的某些次级业务中,例如:

员工离开/更改人事系统后,其他从属应用程序将用于数据同步.

在某些项目中,公司其他部门的应用程序服务可能需要同步我们的人事系统的某些组织结构数据,但是当人事系统数据发生更改时,应用程序的依赖方需要同步数据. 在这种情况下,因为员工的离职/变更操作不是很频繁,所以它们可以有效地防止线程阻塞,并且基本上不需要并发和吞吐量. 因此,数据可以存储在ArrayBlockingQueue中,并由依赖方应用程序服务进行同步.

功能:

LinkedBlockingQueue是基于链接列表实现的. 队列容量默认为Integer.MAX_VALUE用于存储/检索数据的操作,这些操作具有独立的锁,可以并行执行.

java的queue_java queue的实现类_java queue 实现类

分析: 1.根据链表,添加和删除数据的速度比数组快,但是每次存储/删除数据时,都会有新的和删除的Node对象,因此也存在GC的可能性影响性能2.默认容量非常大,因此基本上不会阻塞存储数据的线程,但是如果使用速度太低,则内存使用率可能会飙升. 3.读/取操作锁是分开的,因此它适合具有并发性和吞吐量要求的项目

使用场景: 在某些项目的核心业务具有相似的生产和消费速度的场景中:

通过电子邮件/短信提醒您完成订单.

当用户在订单系统中成功下订单时,信息将被放入ArrayBlockingQueue,消息推送系统将数据推出以推送消息以提醒用户订单成功.

如果订单的交易量很大,则使用ArrayBlockingQueue会出现一些问题. 固定阵列很容易用完. 这时,调用线程将进入该块,因此消息可能无法及时推出,因此请使用LinkedBlockingQueue比较“适当”,但应注意消耗率不应太低,否则内存将被占用. 容易用完(通常不会一直产生消息,但是有必要防止消息的积累)

比较ArrayBlockingQueue: 实际上,对于ArrayBlockingQueue和LinkedBlockingQueue,在处理普通的生产者-消费者问题时,通常可以互换使用两者.

这里也有详细说明. 有人可能会问为什么我不使用MQ或Redis: 我认为很多技术知识具有相同的使用场景,这很普遍,使用MQ / Redis或阻塞队列,我们​​需要考虑项目哪种方案最合适在中国?如果我们有现成的MQ / Redis,并且公司的前任拥有使用该功能的良好包装,或者业务需求必须使用MQ,那么我们的项目就不会有任何问题. 但是,如果没有现成的MQ / Redis或现成的封装,并且业务相对单一,那么使用阻塞队列来简单地编写一个小的函数来实现也是非常好的,当然,如果您学习这些中间件,然后再讨论.

功能: 基于数组实现,最大队列容量为Integer.MAX_VALUE-8(由于数组的对象标头减去8).

根据进入的优先级进行排序,以确保根据优先级进行消费

java queue 实现类_java的queue_java queue的实现类

分析优先级阻止队列中是否存在排序. 根据优先级,通过二叉树最小堆排序算法减少了将数据放入头尾排序所导致的损失因子

使用场景: 该项目的优先业务

用于购票的VIP队列(文章末尾的实现代码)

用户购买门票时,会根据用户的不同级别将其放置在团队的最前面,并且在有门票来源时,将根据优先级进行分配

功能: DelayQueue延迟队列java queue的实现类,基于优先级队列要实现存储元素必须实现Delayed接口(Delayed接口继承Comparable接口)

分析: 因为它基于优先级队列,但是它比较时间,所以我们可以根据需要返回到反向或向前序列(通常返回到背面,用于倒计时)

使用场景:

订单超时取消功能

当用户下订单而不付款时,倒计时开始,如果超时,则释放订单中的资源. 如果付款被取消或完成,我们将讨论删除队列中的数据.

java的queue_java queue 实现类_java queue的实现类

倒数网站刷牙问题(文章末尾的实现代码)

逻辑与上面相同

功能: 无空间队列或堆栈的双堆栈双队列算法. 对SynchronousQueue的任何写操作都需要等待,直到对SynchronousQueue进行读操作为止. 任何读取操作都需要等待没有容量的写入操作. 这是一个无缓冲的等待队列. 这是一个不存储元素的阻塞队列,它将直接将任务移交给使用者.

分析: 它等效于一个交换通道,不存储任何元素. 提供者和消费者需要合作完成工作. 缺少一个线程将阻塞线程,直到等待配对

使用场景:

请参阅线程池newCachedThreadPool().

如果我们不确定生产者发出的每个请求的数量,但需要快速处理,这是使用SynchronousQueue将消费者线程分配给每个生产者请求的最简洁方法. Executors.newCachedThreadPool()使用SynchronousQueue. 该线程池根据需要(当新任务到达时)创建新线程. 如果有空闲线程,它们将被重用. 默认情况下,线程在空闲60秒后将被回收.

轻量级任务转移

例如,会话传输,通常代理需要传输会话. 如果有座席,我们将分配一个客户服务,如果没有,则请求线程将被阻止. 一段时间后,它将超时或提示当前代理已满.

public class QueueTest {
static class Ticket implements Comparable<Ticket> {
        private int level;
        public Ticket(int level) {
            this.level = level;
        }
        @Override
        public int compareTo(Ticket o) {
            //优先级高的返回-1
            if (this.level > o.level)
                return -1;
            else
                return 1;
        }
}
public static void main(String[] args) {
        //VIP客户、各大机场的VIP客户的优先登机,加速抢票
        BlockingQueue<Ticket> queue1 = new PriorityBlockingQueue<>();
        Ticket ticket = new Ticket(0);
        Ticket ticket1 = new Ticket(1);
        Ticket ticket2 = new Ticket(2);
        Ticket ticket3 = new Ticket(-1);
        queue1.add(ticket);
        queue1.add(ticket1);
        queue1.add(ticket2);
        queue1.add(ticket3);
        for (; ; ) {
            try {
                System.out.println(queue1.take().level);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class QueueTest {
    static class Work implements Delayed {
        //名称
        private String name;
        //时长
        private long time;
        public Work(String name, long time, TimeUnit unit) {
            this.name = name;
            this.time = System.currentTimeMillis() + (time > 0 ? unit.toMillis(time) : 0);
        }
        //时间
        @Override
        public long getDelay(TimeUnit unit) {
            return time - System.currentTimeMillis();
        }
        @Override
        public int compareTo(Delayed o) {
            Work work = (Work) o;
            long diff = this.time - work.time;
            if (diff <= 0) {// 改成>=会造成问题
                return -1;
            } else {
                return 1;
            }
        }
    }
public static void main(String[] args) {
        BlockingQueue<Work> queue3 = new DelayQueue<>();
        try {
            Work work = new Work("用户一", 25, TimeUnit.SECONDS);
            Work work2 = new Work("用户二", 5, TimeUnit.SECONDS);
            Work work3 = new Work("用户三", 15, TimeUnit.SECONDS);
            queue3.add(work);
            queue3.add(work2);
            queue3.add(work3);
            for (; ; ) {
                Work work1 = queue3.take();
                System.out.println(work1.name + "," + work1.time);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

以上是作者对阻塞线程的五个主要实现方案的分析. 如果有缺陷,请发表评论.


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-264324-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...