BlockingQueue

2023-05-16

BlockingQueue

一、阻塞队列基本方法介绍

谈到线程池,不得不谈到生产者-消费者模式,谈到生产者-消费者,就不得不谈到对应的数据结构,谈到对应的数据结构不得不言BlockingQueue

顾名思义,BlockingQueue翻译为阻塞队列。队列无非两种操作:入队和出队。而针对于入队出队的边界值的不同,分为几个方法:

抛出异常

特殊值

阻塞

超时

插入

add(e)

offer(e)

put(e)

offer(e, time, unit)

移除

remove()

poll()

take()

poll(time, unit)

检查

element()

peek()

不可用

不可用

测试代码:

public class QueueTest {

    public static void main(String args[]) {

        final BlockingQueue queue = new ArrayBlockingQueue(5);

        init(queue);

        System.out.println("queue.size=" + queue.size() + ",    top element:" + queue.element());

        // queue.add("f");  //1. add方法:队满加入抛异常

        /*boolean bool = queue.offer("f");  //2. offer方法,队满加入会返回:false

        System.out.println("queue.size=" + queue.size() + ",   入队结果:" + bool);*/

 /*       try {

            queue.put("f");  //3.put方法,队满put会阻塞,下边的systemout方法不会执行,直至有消费者take出去

        } catch (InterruptedException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        }

        System.out.println("queue.size=" + queue.size() + ",   put结束:");*/

        Thread thread1 = new Thread(new Runnable() {

            public void run() {

                boolean bool = false;

                try {

                    bool = queue.offer("f", 5, TimeUnit.SECONDS); //5.offer带时间参数:当队满时,如果等待一定时间内还是满的就返回false,如果在这个期间队有空间了就可以放入一个元素,返回

                    System.out.println("queue.size=" + queue.size() + ",   入队结果:" + bool);

                } catch (InterruptedException e) {

                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

                }

            }

        });

        thread1.start();

        //我们开一个消费者线程做出队操作,以便上述的offer可以正常加入

        Thread thread = new Thread(new Runnable() {

            public void run() {

                while (queue.size() > 0) {

                    try {

                        String str = (String) queue.take();

                        System.out.println("queue.size=" + queue.size() + ",   出队结果:" + str);

                        Thread.sleep(500);

                    } catch (InterruptedException e) {

                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

                    }

                }

            }

        });

        thread.start();

    }

    private static void init(BlockingQueue queue) {

        queue.add("a");

        queue.add("b");

        queue.add("c");

        queue.add("d");

        queue.add("e");

    }

}

add:入队,如果队列满会抛出异常。

Exception in thread "main" java.lang.IllegalStateException: Queue full

at java.util.AbstractQueue.add(AbstractQueue.java:71)

at java.util.concurrent.ArrayBlockingQueue.add(ArrayBlockingQueue.java:209)

源码:

    public boolean add(E e) {

        if (offer(e)) 

            return true; //如果加入成功,返回true

        else

            throw new IllegalStateException("Queue full"); //如果添加失败,抛异常

    }

Offer:入队,如果队满会返回false

boolean bool = queue.offer("f");  //offer方法会返回:false

源码:

    public boolean offer(E e) {

        if (e == null) throw new NullPointerException();

        final ReentrantLock lock = this.lock;

        lock.lock();

        try {

            if (count == items.length)

                return false; //返回失败

            else {

                insert(e);

                return true; //返回成功

            }

        } finally {

            lock.unlock();

        }

    }

Put:入队,如果队满会阻塞

        try {

            queue.put("f");

        } catch (InterruptedException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        }

         System.out.println("queue.size=" + queue.size() + ",   put结束:" );

源码:

    public void put(E e) throws InterruptedException {

        if (e == null) throw new NullPointerException();

        final E[] items = this.items;

        final ReentrantLock lock = this.lock;

        lock.lockInterruptibly();

        try {

            try {

                while (count == items.length)

                    notFull.await(); //阻塞在这儿

            } catch (InterruptedException ie) {

                notFull.signal(); // propagate to non-interrupted thread

                throw ie;

            }

            insert(e);

        } finally {

            lock.unlock();

        }

    }

Offer:带时间的,会有一个缓冲时间,若超过此期间插入失败则失败。

queue.size=5,    top element:a

queue.size=4,   出队结果:a

queue.size=5,   入队结果:true

queue.size=4,   出队结果:b

queue.size=3,   出队结果:c

queue.size=2,   出队结果:d

queue.size=1,   出队结果:e

queue.size=0,   出队结果:f

源码:

  public boolean offer(E e, long timeout, TimeUnit unit)

        throws InterruptedException {

        if (e == null) throw new NullPointerException();

long nanos = unit.toNanos(timeout);

        final ReentrantLock lock = this.lock;

        lock.lockInterruptibly();

        try {

            for (;;) { //轮询

                if (count != items.length) {

//如果有其他线程消费元素,队列不满了,才可以插入元素

                    insert(e);

                    return true;

                }

                if (nanos <= 0)//如果到了约定时间没有插入成功,返回false

                    return false;

                try {

                    nanos = notFull.awaitNanos(nanos); //轮询减时间

                } catch (InterruptedException ie) {

                    notFull.signal(); // propagate to non-interrupted thread

                    throw ie;

                }

            }

        } finally {

            lock.unlock();

        }

    }

出队的几种形式与入队对应,实例略。

从上述源码也可以看出,BlockingQueque还有几个特点:

1. 不接受null值。

2. 线程安全,方法都用了Lock

3. 最最精华的部分:生产者-消费者模型。

二、生产者-消费者模型

实例:

public class BlockingQueueTest {

    private static AtomicInteger count = new AtomicInteger(0);

    private static AtomicInteger countCreate = new AtomicInteger(0);

public static void main(String args[]) {

    //定义一个阻塞队列,存放文件信息

        BlockingQueue fileQueue = new ArrayBlockingQueue(5);

        String path = "F:\\Song";

        File root = new File(path);

        //生产者线程去遍历文件,放入队列

        FileCrawler fileCrawler = new FileCrawler(fileQueue, root);

        //消费者线程去遍历队列,取出文件

        Indexer indexer = new Indexer(fileQueue);

        //开启几个生产者线程开始遍历文件

        for (File file : root.listFiles()) {

            new Thread(new FileCrawler(fileQueue, file)).start();

        }

         //开启7个消费者者线程开始取出文件

        for (int i = 0; i < 7; i++) {

            new Thread(new Indexer(fileQueue)).start();

        }

        try {

            Thread.sleep(2000);

        } catch (InterruptedException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        }

        System.out.println("生产者生产:" + countCreate.get());

        System.out.println("消费者取到:" + count.get());

    }

    static class FileCrawler implements Runnable {

        private final BlockingQueue fileQueue;

        private final File root;

        FileCrawler(BlockingQueue fileQueue, File root) {

            this.fileQueue = fileQueue;

            this.root = root;

        }

        public void run() {

            try {

                System.out.println("生产者开始生产:" + fileQueue.size());

                crawl(root);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

        private void crawl(File root) throws InterruptedException {

            File[] files = root.listFiles();

            if (files != null) {

                for (File file : files) {

                    if (file.isDirectory()) {

                        crawl(file);

                    } else {

                        fileQueue.put(file); //put

                        countCreate.incrementAndGet();

                    }

                }

            }

        }

    }

    static class Indexer implements Runnable {

        private final BlockingQueue fileQueue;

        Indexer(BlockingQueue fileQueue) {

            this.fileQueue = fileQueue;

        }

        public void run() {

            while (true) {

                try {

                    System.out.println("消费者开始消费:" + fileQueue.size());

                    File file = (File) fileQueue.take(); //take

                    count.incrementAndGet();

                    System.out.println(file.getName());

                } catch (InterruptedException e) {

                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

                }

            }

        }

    }

}

三、阻塞队列的实现类

基本的任务排队方式有三种:

有界:ArrayBlockingQueue: 一个由数组支持的有界阻塞队列。

无界:LinkedBlockingQueue: 一个基于已链接节点的、范围任意的blocking queue

同步移交:SynchronousQueue: 同步队列,puttake串行执行。生产者对其的插入操作必须等待消费者的移除操作,反之亦然。同步队列类似于信道,它非常适合传递性设计,在这种设计中,在一个线程中运行的对象要将某些信息、事件或任务传递给在另一个线程中运行的对象,它就必须与该对象同步。

synchronousQueue的思想:

参考:http://ifeve.com/java-synchronousqueue/

实例:

public class SynchroNousQueueTest {

    public static void main(String args[]) {

//        final SynchronousQueue synchronousQueue = new SynchronousQueue();

        SynchroNousQueueTest synchroNousQueueTest = new SynchroNousQueueTest();

        final MyShnchronouseQueue<String> synchronousQueue = synchroNousQueueTest.new MyShnchronouseQueue<String>();

        //1。开启一个生产者线程

        Thread threadPut = new Thread(new Runnable() {

            public void run() {

                try {

                    for (int i = 0; i < 10; i++) {

                        synchronousQueue.put(i + "");

                        System.out.println("synchronousQueue,insert element:" + i);

                    }

                } catch (InterruptedException e) {

                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

                }

            }

        });

        //2。开启一个消费者线程

        Thread threadTask = new Thread(new Runnable() {

            public void run() {

                try {

                    for (int i = 0; i < 10; i++) {

                        synchronousQueue.take();

                        System.out.println("synchronousQueue,output element:" + i);

                    }

                } catch (InterruptedException e) {

                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

                }

            }

        });

        threadPut.start();

        threadTask.start();

    }

    class MyShnchronouseQueue<E> {

        Lock lock = new ReentrantLock();

        Condition isFull = lock.newCondition();

        Condition isEmpty = lock.newCondition();

        boolean flag = false;   //同步开关

        E item = null;     //只有一个元素

        public void put(E e) throws InterruptedException {

            lock.lock();

            try {

                while (flag) {    // 当开关为true时,put阻塞,一直await

                    isEmpty.await();

                }

                //当开关为false之后,改为trueitem设值,唤醒消费者消费

                flag = true;

                item = e;

                isFull.signalAll();

            } catch (Exception e1) {

                e1.printStackTrace();

            } finally {

                lock.unlock();

            }

        }

        public synchronized E take() throws InterruptedException {

            lock.lock();

            try {

                while (!flag) {      // 当开关为false时,take阻塞,一直await

                    isFull.await();

                }

                //当开关为true之后,改为false,获取item的值,唤醒生产者生产

                flag = false;

                E e = item;

                item = null;

                isEmpty.signalAll();

                return e;

            } catch (Exception e1) {

                e1.printStackTrace();

            } finally {

                lock.unlock();

            }

            return null;

        }

    }

}

结果:

synchronousQueue,insert element:0

synchronousQueue,output element:0

synchronousQueue,output element:1

synchronousQueue,insert element:1

synchronousQueue,insert element:2

synchronousQueue,output element:2

synchronousQueue,insert element:3

synchronousQueue,output element:3

synchronousQueue,insert element:4

synchronousQueue,output element:4

synchronousQueue,insert element:5

synchronousQueue,output element:5

synchronousQueue,insert element:6

synchronousQueue,output element:6

synchronousQueue,insert element:7

synchronousQueue,output element:7

synchronousQueue,insert element:8

synchronousQueue,output element:8

synchronousQueue,insert element:9

synchronousQueue,output element:9

四、线程池的选择:

根据这些队列的不同特性,我们的线程池也定义了不同的类别:

单一线程池:可以看到corePoolSize=1

    public static ExecutorService newSingleThreadExecutor() {

        return new FinalizableDelegatedExecutorService

            (new ThreadPoolExecutor(1, 1,

                                    0L, TimeUnit.MILLISECONDS,

                                    new LinkedBlockingQueue<Runnable>()));

    }

固定大小线程池:corePoolSizemaximumPoolSize固定,

    public static ExecutorService newFixedThreadPool(int nThreads) {

        return new ThreadPoolExecutor(nThreads, nThreads,

                                      0L, TimeUnit.MILLISECONDS,

                                      new LinkedBlockingQueue<Runnable>());

    }

无界线程池:maximumPoolSizeInteger.MAX_VALUE

    public static ExecutorService newCachedThreadPool() {

        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

                                      60L, TimeUnit.SECONDS,

                                      new SynchronousQueue<Runnable>());

    }

前两者默认情况下将使用一个无界的LinkedBlockingQueue。如果所有工作者线程都处于忙碌状态,那么任务将在队列中等候。如果任务持续快速地到达,并且超过了线程池处理他们的速度,那么队列将无限制地增加。

一种更稳妥的资源管理策略是使用有界队列,例如ArrayBlockingQueue、有界的LinkedBlockingQueuePriorityBlockingQueue。有界队列有助于避免资源耗尽的情况发生,但它又带来了新的问题:当队列填满后,新的任务该怎么办?(这就需要一些饱和策略)在使用有界队列工作时,队列的大小与线程池的大小必须一起调节。如果线程池较小而队列较大,那么有助于减少内存使用量,降低CPU的使用率,同时可以减少上下文切换,但付出的代价是可能会限制吞吐量。

对于非常大的或者无界的线程池,可以通过使用SynchronousQueue来避免任务排队,以及直接将任务从生产者移交给工作者线程。SynchronousQueue不是一个真正的队列,而是一种在线程之间进行移交的机制。要将一个元素放入SynchronousQueue中,必须有另一个线程正在等待接受这个元素。如果没有线程正在等待,并且线程池的当前大小小于最大值,那么ThreadPoolExecutor将创建一个新的线程,否则根据饱和策略,这个任务将被拒绝。使用直接移交将更高效,因为任务会直接移交给执行它的线程,而不是被首先放在队列中,然后由工作者线程从队列中提取该任务。只有当线程池是无界或者可以拒绝任务时,SynchronousQueue才有实际价值。

对于ExecutornewCachedThreadPool工厂方法是一种很好的默认选择。它能提供比固定大小的线程池更好的排队性能。当需要限制当前任务的数量以满足资源管理需求时,那么可以选择固定大小的线程池,就像在接受网络客户请求的服务器应用程序中,如果不进行限制,那么狠容易发生过载问题。

从另一个维度来看:cpu密集型任务,由于cpu使用率一直很高,这时的线程不宜过多,建议配置尽可能小的线程,如配置Ncpu+1个线程的线程池。IO密集型任务由于线程并不是一直在执行任务,IO比较频繁,所以可以配置较多的线程,如2*Ncpu

推荐资料:

http://www.uml.org.cn/j2ee/201212193.asp

http://ifeve.com/java-synchronousqueue/

http://www.cnblogs.com/xiaoQLu/archive/2013/05/13/2870588.html

http://www.cnblogs.com/rilley/archive/2012/02/07/2341767.html 源码注释

http://xtu-xiaoxin.iteye.com/blog/647744

http://www.blogjava.net/xylz/archive/2010/07/30/327582.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

BlockingQueue 的相关文章

  • 07_阻塞队列(BlockingQueue)

    目录 1 什么是BlockingQueue 2 认识BlockingQueue 3 代码演示 栈与队列概念 栈 Stack xff1a 先进后出 xff0c 后进先出 队列 xff1a 先进先出 1 什么是BlockingQueue 在多线
  • BlockingQueue深入分析

    1 BlockingQueue 定义的常用方法如下 抛出异常特殊值阻塞超时插入add e offer e put e offer e time unit 移除remove poll take poll time unit 检查element
  • BlockingQueue

    BlockingQueue 一 阻塞队列基本方法介绍 谈到线程池 xff0c 不得不谈到生产者 消费者模式 xff0c 谈到生产者 消费者 xff0c 就不得不谈到对应的数据结构 xff0c 谈到对应的数据结构不得不言 BlockingQu
  • 阻塞队列-BlockingQueue

    对于Queue而言 xff0c BlockingQueue是主要的线程安全的版本 xff0c 具有阻塞功能 xff0c 可以允许添加 删除元素被阻塞 xff0c 直到成功为止 xff0c blockingqueue相对于Queue而言增加了
  • BlockingQueue深入分析

    1 BlockingQueue 定义的常用方法如下 抛出异常特殊值阻塞超时插入add e offer e put e offer e time unit 移除remove poll take poll time unit 检查element
  • Java 阻塞队列--BlockingQueue

    1 什么是阻塞队列 xff1f 阻塞队列 xff08 BlockingQueue xff09 是一个支持两个附加操作的队列 这两个附加的操作是 xff1a 在队列为空时 xff0c 获取元素的线程会等待队列变为非空 当队列满时 xff0c
  • ArrayBlockingQueue

    在java多线程操作中 BlockingQueue
  • Feign 使用 @SpringQueryMap 来解决多参数传递问题

    本文目录 1 Feign传递一个bean对象参数 2 Feign传递一个bean对象参数 多个基本类型参数 3 Feign传递多个基本类型参数 4 Feign传递多个bean对象参数 在实际项目开发过程中 我们使用 Feign 实现了服务与
  • 如何并行等待多个阻塞队列?

    我有两个独立的阻塞队列 客户端通常使用第一个或第二个阻塞队列来检索要处理的元素 在某些情况下 客户端对两个阻塞队列中的元素感兴趣 无论哪个队列首先提供数据 客户端如何并行等待两个队列 您可以尝试使用poll某种循环中的方法 仅在轮询另一个队
  • 有没有办法保存最大 1 MB 的“消息”集合并将结果写入 JSON/CSV 文件

    我有一个阻塞队列 它不断通过某些应用程序获取消息 现在在 asp net 应用程序中 我尝试使用该队列并将输出写入 CSV JSON 文件 在这里 我想保存最多 1MB 的消息 这些消息从阻塞队列接收 然后将其写出 现在再次保存 1MB 的
  • Java中可以使用Semaphore实现阻塞队列吗?

    我想知道是否可以使用Semaphore来实现阻塞队列 在下面的代码中 我使用一个信号量来保护关键部分 并使用另外两个信号量对象来跟踪空槽和已填充对象的数量 public class BlockingQueue private List qu
  • Mediacodec,解码来自服务器的字节数据包并将其渲染在表面上

    我对 MediaCode 有一些问题 我有 3 个组件 解码器 下载器和渲染器 又简单FragmentStreamVideo初始化 SurfaceView 和 Downloader 其他组件 例如渲染器和解码器 在 SurfaceView
  • 生产者消费者 - ExecutorService 和 ArrayBlockingQueue

    我想知道我对使用 ExecutorService 和 ArrayBlockingQueue 的生产者消费者设计的理解是否正确 我知道有不同的方法来实现这个设计 但我想 最终 这取决于问题本身 我必须面对的问题是 我有一个制作人 他从一个大文
  • 多生产者多消费者多线程Java

    我正在尝试生产者 消费者问题的多个生产者 多个消费者用例 我使用 BlockingQueue 在多个生产者 消费者之间共享公共队列 下面是我的代码 Producer import java util concurrent BlockingQ
  • 异步通知 BlockingQueue 有可用项目

    我需要一个Object当某些情况时得到异步通知BlockingQueue有一件物品要赠送 我在 Javadoc 和网络上搜索了一个预制的解决方案 然后我最终得到了我的一个 也许是幼稚的 解决方案 如下 interface QueueWait
  • 为什么 LogWriter 中的竞争条件会导致生产者阻塞? 【并发实践】

    首先 为了防止那些不喜欢读到我已读完的人将问题标记为重复生产者 消费者日志服务以不可靠的方式关闭 https stackoverflow com questions 31626772 producer consumer logging se
  • 如何阻塞直到BlockingQueue为空?

    我正在寻找一种方法来阻止直到BlockingQueue是空的 我知道 在多线程环境下 只要有生产者将物品放入BlockingQueue 可能会出现队列变空 几纳秒后又充满项目的情况 但是 如果只有one生产者 那么它可能希望在停止将项目放入
  • 在java中实现你自己的阻塞队列

    我知道这个问题之前已经被问过并回答过很多次了 但我只是无法根据互联网上找到的示例找出窍门 例如this http tutorials jenkov com java concurrency blocking queues html or t
  • 如何为信号量中等待的线程提供优先级?

    我使用信号量来限制访问函数的线程数量 我希望接下来要唤醒的线程应该由我将给出的某个优先级选择 而不是默认信号量唤醒它们的方式 我们怎样才能做到这一点 这是实现 class MyMathUtil2 implements Runnable do
  • LinkedBlockingQueue 抛出 InterruptedException

    我有这段代码 ALinkedBlockingQueue应该只抛出一个Exception如果在等待添加到队列时被中断 但这个队列是无限的 所以它应该尽快添加 为什么我的关闭方法会抛出一个InterruptedException private

随机推荐

  • uni app项目中实现vue和html通信

    vue实现 web view 是一个 web 浏览器组件 xff0c 可以用来承载网页的容器 xff0c 会自动铺满整个页面 个人业务 xff08 需要实现一个本地的html文件的内嵌 xff09 xff0c 由于web view是自动铺满
  • uni app实现中英文语言切换

    因为业务需求很多app都是可以多种语言进行切换的 xff0c 以此来方便用户的使用 做语言的切换一定要开发开始的时候就规划好 xff0c 不然确实太麻烦了 xff0c 我是后期开发的语言切换 xff0c 好多个页面都需要进行修改 main
  • uniapp一套代码开发app和微信小程序

    为什么选择uniapp开发 xff1f 为什么选择uniapp进行开发 xff1f 1 uniapp对于独自开发是相当友好的 xff0c 一套代码可以兼容app xff08 安卓 xff0c ios xff09 小程序 xff0c h5等
  • python + selenium的使用 - mac可能出现的问题

    注意服务器部署selenium时 xff0c 代码中一定要添加关闭浏览器驱动的语句 xff08 代码执行结束后不会自动关闭浏览器驱动 xff09 xff0c 否则会导致服务器磁盘被占满 1 安装selenium pip span class
  • 使用Truffle 和 Ganache编译、发布智能合约

    文章目录 Truffle开发框架步骤1 安装Truffle2 查看安装是否成功3 创建没有合约的空工程 xff0c 可以使用 truffle init4 编译Truffle项目的合约truffle compile编译问题 5 构建文件Art
  • 基于Ganache和MetaMask搭建以太坊私有网络

    使用Truffle 和 Ganache 编译 发布智能合约 请参考作者博客https blog csdn net weixin 43958804 article details 109576016 操作步骤 下载ganache https
  • python面试题--统计文件中字母出现的次数

    统计字母出现的次数 fp span class token operator 61 span span class token builtin open span span class token punctuation span span
  • 迁移EFI分区至固态硬盘

    接上回 加装SSD后的第二天 xff0c 我发现原来20s开机的电脑居然变成了30s开机 于是我就开始思考什么问题导致了这个情况 xff0c 根据启动顺序问题 xff0c 我发现可能是安装系统时 xff0c 我没拔下HDD的SATA0接口的
  • go defer,panic,recover详解 go 的异常处理

    转载 https www jianshu com p 63e3d57f285f golang中defer panic recover是很常用的三个特性 xff0c 三者一起使用可以充当其他语言中try catch 的角色 xff0c 而de
  • 重新在虚拟机上安装了centOS7系统

    参考教程 xff1a VMware 安装 Centos7 超详细过程 菜鸟教程
  • centOS安装

    1 安装ImageMagick yum install y ImageMagick 2 安装GhostScript yum install y ghostscript 验证是否安装成功 gs version 3 安装libreoffice
  • 10问10答:你真的了解线程池吗?

    Java开发手册 中强调 xff0c 线程资源必须通过线程池提供 xff0c 而创建线程池必须使用ThreadPoolExecutor 手册主要强调利用线程池避免两个问题 xff0c 一是线程过渡切换 xff0c 二是避免请求过多时造成OO
  • TensorRT 加载模型onnx报错: Error Code 10: Internal Error (Could not find any implementation for node

    1 背景 在TensorRT加载ONNX文件 bert模型 xff09 过程出现如标题所示的错误信息 在相同的代码 xff0c 相同的TensorRT版本 xff0c 在3090 xff08 43 win10 xff09 可以进行正常加载和
  • 【Git】在IDEA拉取master分支到你的开发分支上

    git checkout到master2 git pull xff0c 拉去master最新代码 3 git checkout到你的开发分支 右键项目 选择远程master 确定后如果有冲突 xff0c 则解决冲突即可 弄完最后git pu
  • UNIX环境高级编程-第一章

    1 UNIX体系结构 xff1a 严格意义上说 xff0c 可将操作系统定义为一种软件 xff0c 它控制计算机硬件资源 xff0c 提供程序运行环境 我们通常将这种软件称为内核 xff0c 因为它相对较小 xff0c 而且位于环境的核心
  • AP6275S移植总结

    RK3308B 43 AP6275S移植 在rk3308b平台移植rtl8821cs rlt8821cs是wifi 43 bt一体的模组 xff0c 主要记录下移植过程中需要注意的地方 移植驱动 将rtl8821cs的驱动包复制到rk的SD
  • float类型

    float类型遵循IEEE754标准 xff0c 该标准为32位浮点数规定了二进制表示形式 IEEE754采用二进制的科学计数法来表示浮点数 对于float浮点数 xff0c 用1位表示数字的符号 xff08 浮点数正负性 xff0c 0正
  • 判断点与直线的位置关系

    判断点与直线的位置关系是计算几何里面的一个最基本算法 xff0c 可以使用向量来判断 定义 xff1a 平面上三个点A x1 y1 B x2 y2 C x3 y3 xff0c 判断点C与 A B overr
  • 【知识点总结】大数据技术原理与应用

    大数据技术原理与应用 本文是对 大数据与云计算导论 课程知识点的应试总结 基本涵盖了 大数据技术原理与应用 的重点内容 思维导图由 64 福尔摩东整理 第一章 大数据概述 1 三次信息化浪潮 信息化浪潮发生时间标志解决的问题代表企业第一次浪
  • BlockingQueue

    BlockingQueue 一 阻塞队列基本方法介绍 谈到线程池 xff0c 不得不谈到生产者 消费者模式 xff0c 谈到生产者 消费者 xff0c 就不得不谈到对应的数据结构 xff0c 谈到对应的数据结构不得不言 BlockingQu