【LinkedBlockingQueue的API】 1.offer(添加数据) 2.isEmpty+ drainTo(批量消费) 3.poll 4.take

最佳实践:

package org.example;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class testLinkedBlockingQueue {
    public static void main(String[] args) throws Exception {
        // 2个线程之间的交互数据
        BlockingQueue data = new LinkedBlockingQueue<>();

        // step1: 生产者
        // 实际项目中,则是Netty服务端接收到客户端发来的数据
        new Thread(() -> {
            int i = 0;
            while (true) {
                try {
                    data.put(i++);
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        // step2: 消费者
        // 实际项目中,是业务线程池不断的取出任务并执行
        new Thread(() -> {
            while (true) {
                try {
                    // 最佳实践:
                    // 如果没有任务,则让出cpu
                    if(data.isEmpty()){
                        sleep(5);
                        continue;
                    }

                    Collection tasks = new LinkedList<>();
                    data.drainTo(tasks);
                    for(Runnable task : tasks){
                        task.run();
                    }
                    
        
                    // ---------------下面是一些其它使用方式-----------------

                    // 使用方式1:不发生阻塞,这样子心跳下面的模块还能正常更新(用于游戏服
                    // 务器机器人心跳)
                    // 当然了,可以用上面的drainTo用法代替
                    while (!data.isEmpty()) {
                        System.out.println(data.poll());
                        // TODO 解析data数据,并进行消息handler的业务处理
                    }

                    // TODO 其它业务逻辑处理,如:module的更新
                    TimeUnit.MILLISECONDS.sleep(100);


                    // 使用情景2:队列为空则会发生阻塞(用于游戏服务器单线程池处理业务消
                    // 息)
                    // 但是这样子,会让当前线程阻塞挂起,可用drainTo方法代替
                    Integer take = data.take();
                    System.out.println(take);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }
}

总结:

API 1:一个线程往另外一个线程里添加数据

        offer(常用) // 添加数据。 add则是队列满了有异常,因此不要用add

API2: 另外一个线程判断是否自己队列中有数据,有则全部取出来,并执行,没数据则sleep一下。// 感觉更合理

        isEmpty() // 判断队列中是否有数据

        xx.drainTo(yy) (常用) // 把xx中的数据全部取出来放到普通的队列中,并清空自己

下面2个项目中有使用,但是我觉得以后不会在我的代码中出现了:

        poll  // 队列空,也会返回只不过返回的是null,不会阻塞,。     

while(!data.isEmpty()){
     Xxx xx = data.poll();    
}          


poll方法源码:
   public E poll() {
        final AtomicInteger count = this.count;
        if (count.get() == 0)
            return null;
        final E x;
        final int c;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lock();
        try {
            if (count.get() == 0)
                return null;
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }

        take方法 // 队列为空,无数据时阻塞线程,也可用于线程间通信

你可能感兴趣的:(#,java多线程,java,开发语言)