ITPub博客

首页 > 应用开发 > Java > Java学习笔记(四)- 手写循环队列,实现多生产者单消费者

Java学习笔记(四)- 手写循环队列,实现多生产者单消费者

Java 作者:喝水会长肉 时间:2021-12-11 18:21:24 0 删除 编辑

 学习的最好方式就是写出来

今天我们就手撸一个循环队列吧,多生产者,单消费者模式,模拟队列满了之后的场景

这里先说明下循环队列的实现原理

  • 队列长度固定,队列有头部指针(front)、尾部指针(rear)两个指针

  • 每插入一个元素,尾部指针前移一位

  • 每取出一个元素,头部指针前移一位

  • 队列满了之后,取出一个元素,再加入一个元素,尾部指针归零

  • 取元素的个数达到队列最大长度之后,头部指针归零

1、下面上代码实操,先来个接口类


package com
.fss
.util
.queue
;


public interface Queue < T > {

    /**
    * 添加元素
    */

   boolean push ( T t ) ;

    /**
    * 取出元素,先进先出
    */

    T pop ( ) ;

    /**
    * 判断队列是否已满
    */

   boolean isFull ( ) ;

    /**
    * 判断队列是否为空
    */

   boolean isEmpty ( ) ;

}

2、再来一个抽象类吧,保证子类自己来实现接口


package com
.fss
.util
.queue
;


public abstract class AbstractQueue < T > implements Queue < T > {

   @Override
    public boolean push ( T t ) {
        throw new UnsupportedOperationException ( "不支持的方法" ) ;
    }

   @Override
    public T pop ( ) {
        throw new UnsupportedOperationException ( "不支持的方法" ) ;
    }

   @Override
    public boolean isFull ( ) {
        throw new UnsupportedOperationException ( "不支持的方法" ) ;
    }

   @Override
    public boolean isEmpty ( ) {
        throw new UnsupportedOperationException ( "不支持的方法" ) ;
    }
}

3、队列实现类


package com
.fss
.util
.queue
;


import java .util .Arrays ;

public class CycleQueue < T > extends AbstractQueue < T > implements Queue < T > {

    // 队列初始化大小
    private static final int CAPCAITY = 6 ;

    // 队列头
   volatile int front ;

    // 队列尾
   volatile int rear ;

    // 队列元素
   volatile T [ ] arrays ;

    public CycleQueue ( ) {
        this .arrays = ( T [ ] ) new Object [ CAPCAITY ] ;
    }

    /**
    * 添加元素,队尾下标+1
    */

   @Override
    public boolean push ( T t ) {
        synchronized ( this ) {
            if ( ! isFull ( ) ) {
               arrays [rear ] = t ;
                // 队尾指针+1后的值等于队列容积时,队尾下标重置为0,以实现队列循环使用
                if ( ++rear == CAPCAITY ) {
                   rear = 0 ;
                }
                return true ;
            }
            return false ;
        }
    }

    /**
    * 取出元素,队列头下标+1
    */

   @Override
    public T pop ( ) {
        synchronized ( this ) {
            if ( ! isEmpty ( ) ) {
               System .out . print ( "当前数组: " ) ;
                for (int i = 0 ; i <arrays .length ; i ++ ) {
                   System .out . print (arrays [i ] + "," ) ;
                }
               System .out . print ( " - " ) ;

               final T cur = arrays [front ] ;
               arrays [front ] = null ;
               front ++ ;
                // 队头指针+1后的值等于队列容积时,队头下标重置为0,以实现队列循环使用
                if (front == CAPCAITY ) {
                   front = 0 ;
                }
                return cur ;
            }
            return null ;
        }
    }

    /**
    * 判断队列是否满
    */

   @Override
    public boolean isFull ( ) {
        synchronized ( this ) {
            return front == rear && arrays [rear ] != null ;
        }
    }

    /**
    * 判断队列是否为空
    */

   @Override
    public boolean isEmpty ( ) {
        synchronized ( this ) {
            return front == rear && arrays [rear ] == null ;
        }
    }
}


4、大功告成,现在起3个线程类,2个生产者,1一个消费者,生产速度大于消费速度

  • 生产者(当队列满了之后等待,有元素被取出则继续生产)


package com
.fss
.util
.thread
;


import com .fss .util .queue .CycleQueue ;

import java .util .Random ;

public class PushQueueThread extends Thread {

    private CycleQueue queue ;

    private String threadName ;

    public PushQueueThread ( CycleQueue queue , String threadName ) {
        this .queue = queue ;
        this .threadName = threadName ;
    }
//java学习交流:737251827  进入可领取学习资源及对十年开发经验大佬提问,免费解答!
   @Override
    public void run ( ) {
        synchronized ( queue ) {
            while ( true ) {
               int i = new Random ( ) . nextInt ( 1000 ) ;
                while (queue . isFull ( ) ) {
                    try {
                       System .out . print (threadName + " - 发现队列满了,排队等位中。。。。\n" ) ;
                       queue . wait ( ) ;
                    } catch (InterruptedException e ) {
                       e . printStackTrace ( ) ;
                    }
                }
               queue . push (i ) ;
               System .out . print (threadName + "-放入元素: " + i + "\n" ) ;
                try {
                   queue . wait ( 100 ) ;
                } catch (InterruptedException e ) {
                   e . printStackTrace ( ) ;
                }
            }
        }
    }
}
  • 消费者(取出元素之后通知生产者生产)


package com
.fss
.util
.thread
;


import com .fss .util .queue .CycleQueue ;

import java .util .List ;

public class PopQueueThread extends Thread {

    private CycleQueue queue ;

    private String threadName ;

    public PopQueueThread ( CycleQueue queue , String threadName ) {
        this .queue = queue ;
        this .threadName = threadName ;
    }

   @Override
    public void run ( ) {
        synchronized ( queue ) {
            while ( true ) {
                if ( !queue . isEmpty ( ) ) {
                   Object o = queue . pop ( ) ;
                   System .out . print (threadName + "-取出元素: " +o + "\n" ) ;
                    try {
                       queue . wait ( 100 ) ;
                       System .out . println (threadName + " - 有空位了,下一位上来吧。。。" ) ;
                       queue . notifyAll ( ) ;
                    } catch (InterruptedException e ) {
                       e . printStackTrace ( ) ;
                    }
                } else {
                    try {
                       System .out . print (threadName + " - 发现队列空了,坐等客人上门。。。。\n" ) ;
                       queue . wait ( 200 ) ;
                       queue . notifyAll ( ) ;
                    } catch (InterruptedException e ) {
                       e . printStackTrace ( ) ;
                    }
                }
            }
        }
    }

}

5、起一个main方法测试吧


package test
;


import com .fss .util .queue .CycleQueue ;
import com .fss .util .thread .PopQueueThread ;
import com .fss .util .thread .PushQueueThread ;

public class CycleQueueTest {

    public static void main ( String [ ] args ) {
       CycleQueue queue = new CycleQueue ( ) ;
       PushQueueThread pushThread1 = new PushQueueThread (queue , "Push1" ) ;
       PushQueueThread pushThread2 = new PushQueueThread (queue , "Push2" ) ;
       PopQueueThread popThread = new PopQueueThread (queue , "Pop1" ) ;
       pushThread1 . start ( ) ;
       pushThread2 . start ( ) ;
       popThread . start ( ) ;
    }

}


输出结果

Push1
-放入元素: 
148

Push2 -放入元素: 694
当前数组: 148 , 694 , null , null , null , null , - Pop1 -取出元素 : 148
Push1 -放入元素: 797
Push2 -放入元素: 781
Pop1 - 有空位了,下一位上来吧。。。
当前数组: null , 694 , 797 , 781 , null , null , - Pop1 -取出元素 : 694
Push2 -放入元素: 639
Push1 -放入元素: 390
Push2 -放入元素: 633
Pop1 - 有空位了,下一位上来吧。。。
当前数组: 633 , null , 797 , 781 , 639 , 390 , - Pop1 -取出元素 : 797
Push1 -放入元素: 843
Push2 -放入元素: 945
Pop1 - 有空位了,下一位上来吧。。。
当前数组: 633 , 843 , 945 , 781 , 639 , 390 , - Pop1 -取出元素 : 781
Push2 -放入元素: 33
Push1 - 发现队列满了,排队等位中。。。。
Pop1 - 有空位了,下一位上来吧。。。



 



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70010294/viewspace-2847204/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2021-11-19

  • 博文量
    199
  • 访问量
    86397