opposite column

concept

  • Alignment: first in first out
  • stack: first in, last out
  • A queue is a special kind of linear table
    • Only deletes are allowed on the front of the table and inserts are allowed on the rear of the table
    • Like a stack, a queue is a linear list of restricted operations. The end that performs the insert operation is called the tail of the queue, and the end that performs the delete operation is called the head of the queue.
    • Inserting a queue element into the queue is called enqueuing, and removing a queue element from the queue is called dequeuing
  • sequential queue
    • Every time an element is inserted at the end of the queue, rear is incremented by 1; every time an element is deleted at the head of the queue, front is incremented by 1. As the insertion and deletion operations proceed, the number of queue elements changes continuously, and the storage space occupied by the queue also moves in the continuous space allocated for the queue structure. When front=rear, there are no elements in the queue, which is called an empty queue. When rear increases beyond the allocated contiguous space, the queue can no longer insert new elements, but there is often a large amount of free space that is not occupied at this time, which is the storage unit occupied by the queue elements that have been dequeued.
  • circular queue
    • In the actual use of the queue, in order to make the queue space reusable, the use of the queue is often slightly improved: no matter insertion or deletion, once the rear pointer increases by 1 or the front pointer increases by 1, the allocated queue space is exceeded, let It points to the beginning of this continuous space. If you really increase from MaxSize-1 to 0, you can use the remainder operation rear%MaxSize and front%MaxSize to achieve. This actually imagines the queue space as a ring space, and the storage units in the ring space are used cyclically. The queue managed in this way is also called a circular queue.
    • In a circular queue, when the queue is empty, there is front=rear, and when all the queue space is full, there is also front=rear. In order to distinguish these two cases, it is stipulated that the circular queue can only have MaxSize-1 queue elements at most. When there is only one empty storage unit left in the circular queue, the queue is full. Therefore, the condition that the queue is empty is front=rear, and the condition that the queue is full is front=(rear+1)%MaxSize.
  • Array implementation of queue
    • The queue can be stored in an array Q[1...m], and the upper bound m of the array is the maximum capacity allowed by the queue. In the operation of the queue, two pointers need to be set: head, the head pointer, pointing to the actual head element; tail, the tail pointer, pointing to the next position of the actual tail element.
    • Under normal circumstances, the initial value of the two pointers is set to 0, then the queue is empty and there are no elements. The array defines Q[1…10]. Q(i) i=3,4,5,6,7,8. Head pointer head=2, tail pointer tail=8. The number of elements in the queue is: L=tail-head.
    • Now to dequeue the element at the head of the queue, the head pointer needs to be incremented by 1. That is, when head=head+1, the head pointer moves up one position and points to Q(3), indicating that Q(3) has been dequeued. If you want to enqueue a new element, you need to move the tail pointer up one position. That is, when tail=tail+1, Q(9) joins the queue.
    • When the tail of the queue has been processed at the top, that is, tail=10, if the enqueue operation is to be performed, an "overflow" will occur, but there are actually three empty positions in the queue, so this overflow is called "false" overflow".
    • Queues, like stacks, only allow insertion and deletion of elements at breakpoints.
  • Linked list implementation of queue
    • Queues based on linked lists need to dynamically create and delete nodes, which is inefficient, but can grow dynamically.
    • The FIFO (first in first out) used by the queue, new elements (elements waiting to enter the queue) are always inserted at the end of the linked list, and always read from the head of the linked list when reading. Each time an element is read, one element is freed. The so-called dynamic creation, dynamic release. Therefore, there is no problem such as overflow.
  • Basic operations on queues
    • (1) Initialize the queue: Init_Queue(q), initial condition: the queue q does not exist. Operation result: an empty team is constructed;
    • (2) Enqueue operation: In_Queue(q,x), initial condition: Queue q exists. Operation result: For the existing queue q, insert an element x to the end of the queue, and the queue changes;
    • (3) Dequeue operation: Out_Queue(q,x), initial condition: queue q exists and is not empty, operation result: delete the first element of the queue and return its value, the queue changes;
    • (4) Read the queue head element: Front_Queue(q,x), initial condition: queue q exists and is not empty, operation result: read the queue head element and return its value, the queue remains unchanged;
    • (5) Empty queue operation: Empty_Queue(q), initial condition: queue q exists, operation result: if q is an empty queue, it returns 1, otherwise it returns 0.

java message queue

  • Scenario: When you don't need immediate results, but the concurrency can't be infinite, it's almost when you need to use a message queue .
    • For example, if you write a log, because a client may have multiple operations to write, and there are many clients, obviously the concurrency cannot be infinite, so you need to put the request to write the log into the message queue, on the consumer side The logs generated in the queue are sequentially written to the database.
  • code demo
  • Code source ( http://www.cnblogs.com/jaycekon/p/6225058.html )
  • Create a producer
public class Producter {

    //ActiveMq 的默认用户名
    private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;
    //ActiveMq 的默认登录密码
    private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;
    //ActiveMQ 的链接地址
    private static final String BROKEN_URL = ActiveMQConnection.DEFAULT_BROKER_URL;

    AtomicInteger count = new AtomicInteger(0);
    //链接工厂
    ConnectionFactory connectionFactory;
    //链接对象
    Connection connection;
    //事务管理
    Session session;
    ThreadLocal<MessageProducer> threadLocal = new ThreadLocal<>();

    public void init(){
        try {
            //创建一个链接工厂
            connectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKEN_URL);
            //从工厂中创建一个链接
            connection  = connectionFactory.createConnection();
            //开启链接
            connection.start();
            //创建一个事务(这里通过参数可以设置事务的级别)
            session = connection.createSession(true,Session.SESSION_TRANSACTED);
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }

    public void sendMessage(String disname){
        try {
            //创建一个消息队列
            Queue queue = session.createQueue(disname);
            //消息生产者
            MessageProducer messageProducer = null;
            if(threadLocal.get()!=null){
                messageProducer = threadLocal.get();
            }else{
                messageProducer = session.createProducer(queue);
                threadLocal.set(messageProducer);
            }
           while(true){
                Thread.sleep(1000);
                int num = count.getAndIncrement();
                //创建一条消息
                TextMessage msg = session.createTextMessage(Thread.currentThread().getName()+
                        "productor:我是大帅哥,我现在正在生产东西!,count:"+num);
                System.out.println(Thread.currentThread().getName()+
                        "productor:我是大帅哥,我现在正在生产东西!,count:"+num);
                //发送消息
                messageProducer.send(msg);
                //提交事务
                session.commit();
            }
        } catch (JMSException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 2. Create a consumer
public class Comsumer {

    private static final String USERNAME = ActiveMQConnection.DEFAULT_USER;

    private static final String PASSWORD = ActiveMQConnection.DEFAULT_PASSWORD;

    private static final String BROKEN_URL = ActiveMQConnection.DEFAULT_BROKER_URL;

    ConnectionFactory connectionFactory;

    Connection connection;

    Session session;

    ThreadLocal<MessageConsumer> threadLocal = new ThreadLocal<>();
    AtomicInteger count = new AtomicInteger();

    public void init(){
        try {
            connectionFactory = new ActiveMQConnectionFactory(USERNAME,PASSWORD,BROKEN_URL);
            connection  = connectionFactory.createConnection();
            connection.start();
            session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }


    public void getMessage(String disname){
        try {
            Queue queue = session.createQueue(disname);
            MessageConsumer consumer = null;

            if(threadLocal.get()!=null){
                consumer = threadLocal.get();
            }else{
                consumer = session.createConsumer(queue);
                threadLocal.set(consumer);
            }
            while(true){
                Thread.sleep(1000);
                TextMessage msg = (TextMessage) consumer.receive();
                if(msg!=null) {
                    msg.acknowledge();
                    System.out.println(Thread.currentThread().getName()+": Consumer:我是消费者,我正在消费Msg"+msg.getText()+"--->"+count.getAndIncrement());
                }else {
                    break;
                }
            }
        } catch (JMSException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 3. The producer starts producing information
public class TestMq {
    public static void main(String[] args){
        Producter producter = new Producter();
        producter.init();
        TestMq testMq = new TestMq();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //Thread 1
        new Thread(testMq.new ProductorMq(producter)).start();
        //Thread 2
        new Thread(testMq.new ProductorMq(producter)).start();
        //Thread 3
        new Thread(testMq.new ProductorMq(producter)).start();
        //Thread 4
        new Thread(testMq.new ProductorMq(producter)).start();
        //Thread 5
        new Thread(testMq.new ProductorMq(producter)).start();
    }

    private class ProductorMq implements Runnable{
        Producter producter;
        public ProductorMq(Producter producter){
            this.producter = producter;
        }

        @Override
        public void run() {
            while(true){
                try {
                    producter.sendMessage("Jaycekon-MQ");
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Queue in java (for columns)

  • The Queue interface is at the same level as List and Set, and both inherit the Collection interface. LinkedList implements the Queue interface.
  • The operation of the blocking queue in dk1.5:
add        增加一个元索                     如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove   移除并返回队列头部的元素    如果队列为空,则抛出一个NoSuchElementException异常
element  返回队列头部的元素             如果队列为空,则抛出一个NoSuchElementException异常
offer       添加一个元素并返回true       如果队列已满,则返回false
poll         移除并返问队列头部的元素    如果队列为空,则返回null
peek       返回队列头部的元素             如果队列为空,则返回null
put         添加一个元素                      如果队列满,则阻塞
take        移除并返回队列头部的元素     如果队列为空,则阻塞
  • remove, element, offer, poll, and peek actually belong to the Queue interface.

  • Operations that block queues can be divided into three categories based on how they respond: aad, remove, and element operations throw exceptions when you try to add elements to a full queue or get elements from an empty queue. Of course, in a multithreaded program, the queue can become full or empty at any time, so you might want to use the offer, poll, peek methods. These methods simply give an error message instead of throwing an exception when the task cannot be completed.

  • Note: The poll and peek methods return null on error. Therefore, it is not legal to insert a null value into the queue.

  • There are also variants of the offer and poll methods with timeouts, for example, the following call:

    • boolean success = q.offer(x,100,TimeUnit.MILLISECONDS);
    • Attempt to insert an element to the tail of the queue within 100ms. If successful, return true immediately; otherwise, when the timeout is reached, return false.
  • Likewise, call:
    • Object head = q.poll(100, TimeUnit.MILLISECONDS);
    • If the queue head element is successfully removed within 100 milliseconds, return the head element immediately; otherwise, when the timeout is reached, return null
  • Finally, we have the blocking operations put and take. The put method blocks when the queue is full, and the take method blocks when the queue is empty.
  • Two significant benefits of using blocking queues are:
    • No additional synchronization is required when multiple threads operate on a common queue
    • In addition, the queue will automatically balance the load, that is, if the processing on the other side (the production and consumption sides) is fast, it will be blocked, thereby reducing the processing speed gap between the two sides.
    ArrayBlockingQueue:基于数组实现的一个阻塞队列,在创建ArrayBlockingQueue对象时必须制定容量大小。并且可以指定公平性与非公平性,默认情况下为非公平的,即不保证等待时间最长的队列最优先能够访问队列。

  LinkedBlockingQueue:基于链表实现的一个阻塞队列,在创建LinkedBlockingQueue对象时如果不指定容量大小,则默认大小为Integer.MAX_VALUE。

  PriorityBlockingQueue:以上2种队列都是先进先出队列,而PriorityBlockingQueue却不是,它会按照元素的优先级对元素进行排序,按照优先级顺序出队,每次出队的元素都是优先级最高的元素。注意,此阻塞队列为无界阻塞队列,即容量没有上限(通过源码就可以知道,它没有容器满的信号标志),前面2种都是有界队列。

  DelayQueue:基于PriorityQueue,一种延时阻塞队列,DelayQueue中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue也是一个无界队列,因此往队列中插入数据的操作(生产者)永远不会被阻塞,而只有获取数据的操作(消费者)才会被阻塞。
public class BlockingQueueTest {  
    public static void main(String[] args) {  
        Scanner in = new Scanner(System.in);  
        System.out.print("Enter base directory (e.g. /usr/local/jdk5.0/src): ");  
        String directory = in.nextLine();  
        System.out.print("Enter keyword (e.g. volatile): ");  
        String keyword = in.nextLine();  

        final int FILE_QUEUE_SIZE = 10;// 阻塞队列大小  
        final int SEARCH_THREADS = 100;// 关键字搜索线程个数  

        // 基于ArrayBlockingQueue的阻塞队列  
        BlockingQueue<File> queue = new ArrayBlockingQueue<File>(  
                FILE_QUEUE_SIZE);  

        //只启动一个线程来搜索目录  
        FileEnumerationTask enumerator = new FileEnumerationTask(queue,  
                new File(directory));  
        new Thread(enumerator).start();  

        //启动100个线程用来在文件中搜索指定的关键字  
        for (int i = 1; i <= SEARCH_THREADS; i++)  
            new Thread(new SearchTask(queue, keyword)).start();  
    }  
}  
class FileEnumerationTask implements Runnable {  
    //哑元文件对象,放在阻塞队列最后,用来标示文件已被遍历完  
    public static File DUMMY = new File("");  

    private BlockingQueue<File> queue;  
    private File startingDirectory;  

    public FileEnumerationTask(BlockingQueue<File> queue, File startingDirectory) {  
        this.queue = queue;  
        this.startingDirectory = startingDirectory;  
    }  

    public void run() {  
        try {  
            enumerate(startingDirectory);  
            queue.put(DUMMY);//执行到这里说明指定的目录下文件已被遍历完  
        } catch (InterruptedException e) {  
        }  
    }  

    // 将指定目录下的所有文件以File对象的形式放入阻塞队列中  
    public void enumerate(File directory) throws InterruptedException {  
        File[] files = directory.listFiles();  
        for (File file : files) {  
            if (file.isDirectory())  
                enumerate(file);  
            else  
                //将元素放入队尾,如果队列满,则阻塞  
                queue.put(file);  
        }  
    }  
}  
class SearchTask implements Runnable {  
    private BlockingQueue<File> queue;  
    private String keyword;  

    public SearchTask(BlockingQueue<File> queue, String keyword) {  
        this.queue = queue;  
        this.keyword = keyword;  
    }  

    public void run() {  
        try {  
            boolean done = false;  
            while (!done) {  
                //取出队首元素,如果队列为空,则阻塞  
                File file = queue.take();  
                if (file == FileEnumerationTask.DUMMY) {  
                    //取出来后重新放入,好让其他线程读到它时也很快的结束  
                    queue.put(file);  
                    done = true;  
                } else  
                    search(file);  
            }  
        } catch (IOException e) {  
            e.printStackTrace();  
        } catch (InterruptedException e) {  
        }  
    }  
    public void search(File file) throws IOException {  
        Scanner in = new Scanner(new FileInputStream(file));  
        int lineNumber = 0;  
        while (in.hasNextLine()) {  
            lineNumber++;  
            String line = in.nextLine();  
            if (line.contains(keyword))  
                System.out.printf("%s:%d:%s%n", file.getPath(), lineNumber,  
                        line);  
        }  
        in.close();  
    }  
}  

  • Blocking queue (code source: http://www.cnblogs.com/molao-doing/articles/4445045.html )
  • Function description: Due to the deployment of Alibaba Cloud's SLS log service, a log interface has been written. Considering that the submission of system log volume may be blocked, a thread pool (survivor and consumer mode) is introduced here to maintain the sending of log queues. A message sending module sends the message to the message queue, without waiting for the return result, the sending module continues to perform other tasks. Instructions in the message queue are processed by threads in the thread pool. Use a Queue to store tasks when the thread pool overflows
public class ThreadPoolManager {

    private static ThreadPoolManager tpm = new ThreadPoolManager();

    // 线程池维护线程的最少数量
    private final static int CORE_POOL_SIZE = 4;

    // 线程池维护线程的最大数量
    private final static int MAX_POOL_SIZE = 10;

    // 线程池维护线程所允许的空闲时间
    private final static int KEEP_ALIVE_TIME = 0;

    // 线程池所使用的缓冲队列大小
    private final static int WORK_QUEUE_SIZE = 10;

    // 消息缓冲队列
    Queue<String> msgQueue = new LinkedList<String>();

    // 访问消息缓存的调度线程
    // 查看是否有待定请求,如果有,则创建一个新的AccessDBThread,并添加到线程池中
    final Runnable accessBufferThread = new Runnable() {

        @Override
        public void run() {
            if(hasMoreAcquire()){
                String msg = ( String ) msgQueue.poll();
                Runnable task = new AccessDBThread( msg );
                threadPool.execute( task );
            }
        }
    };


    final RejectedExecutionHandler handler = new RejectedExecutionHandler(){

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            System.out.println(((AccessDBThread )r).getMsg()+"消息放入队列中重新等待执行");
            msgQueue.offer((( AccessDBThread ) r ).getMsg() );
        }
    };

    // 管理数据库访问的线程池

    @SuppressWarnings({ "rawtypes", "unchecked" })
    final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME,
            TimeUnit.SECONDS,new ArrayBlockingQueue( WORK_QUEUE_SIZE ), this.handler);

    // 调度线程池
    final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool( 100 );



    @SuppressWarnings("rawtypes")
    final ScheduledFuture taskHandler = scheduler.scheduleAtFixedRate(accessBufferThread, 0, 1, TimeUnit.SECONDS);

    public static ThreadPoolManager newInstance() {

        return tpm;
    }

    private ThreadPoolManager(){}

    private boolean hasMoreAcquire(){
        return !msgQueue.isEmpty();
    }

    public void addLogMsg( String msg ) {
        Runnable task = new AccessDBThread( msg );
        threadPool.execute( task );
    }
}
  • Threads working in the thread pool
public class AccessDBThread implements Runnable {

    private String msg;

    public AccessDBThread() {
        super();
    }

    public AccessDBThread(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public void run() {

        // 向数据库中添加Msg变量值
        System.out.println("Added the message: "+msg+" into the Database");
    }

}

//TestDriver.java是一个驱动测试,sendMsg方法不间断的向ThreadPoolManager发送数据
public class TestDriver {

    ThreadPoolManager tpm = ThreadPoolManager.newInstance();

    public void sendMsg( String msg ) {

        tpm.addLogMsg( msg + "记录一条日志 " );
    }

    public static void main(String[] args) {
        for(int i=0;i<1000;i++){
            new TestDriver().sendMsg( Integer.toString( i ) );
        }

        //new TestDriver().sendMsg("发起一条对象" );
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326002142&siteId=291194637