队列是什么类?

队列是什么类?,第1张

java中的queue类是队列数据结构管理类。在它里边的元素可以按照添加它们的相同顺序被移除。

队列通常(但并非一定)以 FIFO(先进先出)的方式排序各个元素。不过优先级队列和 LIFO 队列(或堆栈)例外,前者根据提供的比较器或元素的自然顺序对元素进行排序,后者按 LIFO(后进先出)的方式对元素进行排序。无论使用哪种排序方式,队列的头都是调用remove()或poll()所移除的元素。在 FIFO 队列中,所有的新元素都插入队列的末尾。其他种类的队列可能使用不同的元素放置规则。每个Queue实现必须指定其顺序属性。

offer 添加一个元素并返回true 如果队列已满,则返回false

poll 移除并返问队列头部的元素如果队列为空,则返回null

peek 返回队列头部的元素 如果队列为空,则返回null

put 添加一个元素 如果队列满,则阻塞

take移除并返回队列头部的元素 如果队列为空,则阻塞

element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常

add增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常

remove 移除并返回队列头部的元素如果队列为空,则抛出一个

NoSuchElementException异常

注意:poll和peek方法出错进返回null。因此,向队列中插入null值是不合法的。

还有带超时的offer和poll方法重载,例如,下面的调用:

boolean success = q.offer(x,100,TimeUnit.MILLISECONDS)

尝试在100毫秒内向队列尾部插入一个元素。如果成功,立即返回true;否则,当到达超时进,返回false。同样地,调用:

Object head = q.poll(100, TimeUnit.MILLISECONDS)

如果在100毫秒内成功地移除了队列头元素,则立即返回头元素;否则在到达超时时,返回null。

阻塞 *** 作有put和take。put方法在队列满时阻塞,take方法在队列空时阻塞。

Queue接口与List、Set同一级别,都是继承了Collection接口。LinkedList实现了Queue接 口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用。BlockingQueue 继承了Queue接口。

在Java中,BlockingQueue是一个接口,它的实现类有 ArrayBlockingQueue、DelayQueue、 LinkedBlockingDeque、 LinkedBlockingQueue、PriorityBlockingQueue、 SynchronousQueue等,它们的区别主要体现在存储结构上或对元素 *** 作上的不同,但是对于take与put *** 作的原理,却是类似的。

阻塞与非阻塞

LinkedBlockingQueue内部是使用链表实现一个队列的,但是有别于一般的队列,在于该队列至少是有一个节点的,头节点不含有元素。如果队列为空时,头节点的next参数为null。尾节点的next参数也为null。

1、LinkedBlockingQueue不允许插入的元素为null;

2、同一时刻只有一个线程可以进行入队 *** 作,putLock在将元素插入队列尾部时加锁了;

3、如果队列满了,则会调用notFull.await(),将该线程加入到Condition等待队列中。await方法会释放线程占有的锁,这将导致之前由于被阻塞的入队线程将会获取到锁,执行到while循环处,不过可能因为队列仍旧是满的,也被进入到条件队列中;

4、一旦有出队线程取走元素,就会通知到入队等待队列释放线程。那么第一个加入到Condition队列中的将会被释放,那么该线程将会重新获得put锁,继而执行enqueue()方法,将节点插入到队列的尾部;

5、然后得到插入队列前元素的个数,如果插入后队列中还可以继续插入元素,那么就通知notFull条件的等待队列中的线程;

6、如果插入队列前个数为0,那现在插入后,就为1了,那就可以通知因为队列为空而导致阻塞的出队线程去取元素了。

1、同一时刻只有一个线程可以进行出队 *** 作,takeLock在出队之前加锁了;

2、如果队列中元素为空,那就进入notEmpty队列中进行等待。直到队列不为空时,得到队列中的第一个元素。当发现取完发现还有元素可取时,再通知一下notEmpty队列中等待的其他线程。最后判断自己取元素前的是不是满的,如果是满的,那自己取完,就不满了,就可以通知在notFull队列中等待插入的线程进行put了。

LinkedBlockingQueue允许两个线程同时在两端进行入队和出队 *** 作,但一端同时只能有一个线程进行 *** 作,是通过两个锁进行区分的。

为了维护底部数据的统一,引入了AtomicInteger的一个count变量,表示队列中元素的个数。count只能在两个地方变化,一个是入队的方法(进行+1 *** 作),另一个是出队的方法(进行-1 *** 作),而AtomicInteger是原子安全的,所以也就确保了底层队列的数据同步。

ArrayBlockingQueue内部是使用数组实现一个队列的,并且在构造方法中就需要指定容量,也就意味着底层数组一旦创建了,容量就不能改变了,因此ArrayBlockingQueue是一个容量限制的阻塞队列。因此在队列满的时候执行入队会阻塞,在队列为空时出队也会阻塞。

1、ArrayBlockingQueue不允许添加null元素;

2、ArrayBlockingQueue在队列已满的时候,会调用notFull.await(),释放锁并处于阻塞状态;

3、一旦ArrayBlockingQueue在队列不满的时候,就立即入队。

1、取元素时,一旦获得锁,队列为空, 则会阻塞,直至不为空,调用dequeue()出队。

ArrayBlockingQueue是一个底层结构是数组的阻塞队列,是通过 ReentrantLock Condition 来实现的。不可插入为null的元素,入队和出队使用的是同一个锁。意味着同一时刻只能有一个线程能进行入队或者出队 *** 作。入队时,队列已满则会调用notFull.await(),进入阻塞状态。直到队列不满时,再进行入队 *** 作。当出队时,队列为空,则调用notEmpty.await(),进入阻塞状态,直到队列不为空时,则出队。

LinkedBlockingQueue底层实现是链表,ArrayBlockingQueue底层实现是数组

LinkedBlockingQueue默认的队列长度是Integer.Max,但是可以指定容量。在入队与出队都高并发的情况下,性能比ArrayBlockingQueue高很多;

ArrayBlockingQueue必须在构造方法中指定队列长度,不可变。在只有入队高并发或出队高并发的情况下,因为 *** 作数组,且不需要扩容,性能很高。

LinkedBlockingQueue有两把锁,可以有两个线程同时进行入队和出队 *** 作,但同时只能有一个线程进行入队或出队 *** 作。

ArrayBlockingQueue只有一把锁,同时只能有一个线程进行入队和出队 *** 作。

queue不是线程安全的把,List也会扩容,单线程用完全没问题。所以应该是多线程的问题。

你可以这样试试。

1定义一个单例的类,在程序初始化的时候就运行。关于单例类你自行百度。

2单例类里定义一个队列。

3单例类中定义队列的Add方法,把数据加入队列

4.类中开一个线程,循环检测队列,有数据就 *** 作。

public sealed class LuceneNet

    {

        private readonly static LuceneNet one = new LuceneNet()

        private LuceneNet() { }

        public static LuceneNet GetInstance() { return one }

        Queue<LuceneData> queue = new Queue<LuceneData>()

        #region public void AddQueue(LuceneData data) 将数据加入队列

        /// <summary>

        /// 将数据加入队列

        /// </summary>

        /// <param name="data">数据</param>

        public void AddQueue(LuceneData data)

        {

            queue.Enqueue(data)

        }

        #endregion

        #region public void StartThread() 开启一个线程,从队列中取出数据

        /// <summary>

        /// 开启一个线程,从队列中取出数据

        /// </summary>

        public void StartThread()

        {

            ThreadStart threadStart = new ThreadStart(SaveFile)

            Thread thread = new Thread(threadStart)

            thread.IsBackground = true

            thread.Start()

        }

        #endregion

        private void SaveFile()

        {

            while (true)

            {

                if (queue.Count > 0)

                {

                    try

                    {

                        WriteWord()

                    }

                    catch (Exception ex) { throw ex }

                }

                else Thread.Sleep(3000)

            }

        }

        /// <summary>

        /// 将队列中数据写入文件

        /// </summary>

        private void WriteWord()

        {

            //方法

        }

    }


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/bake/11875888.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-19
下一篇 2023-05-19

发表评论

登录后才能评论

评论列表(0条)

保存