第三天..

练习

单词逆序

对于一个字符串,请设计一个算法,只在字符串的单词间做逆序调整,也就是说,
字符串由一些由空格分隔的部分组成,你需要将这些部分逆序。 给定一个原字符串A,
请返回逆序后的字符串。例,输入”I am a boy!“输出”boy! a am I“

输入描述:
输入一行字符串str。(1<=strlen(str)<=10000)

输出描述:
返回逆序后的字符串。

示例 
示例1
输入
It’s a dog!

输出
dog! a It’s
import java.util.ArrayList;
import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);

        String str = scan.nextLine().trim();

        scan.close();

        String[] result = solution(str);


        for (int i = 0; i < result.length; i++){
            System.out.print(result[i] + " ");
        }


    }

    public static String[] solution(String str){
        String[] str1=str.split(" ");
        String[] temp=new String[str1.length];
        for(int i = 0;i<str1.length;i++){
                temp[str1.length-1-i]=str1[i];
        }
        return temp;
    }
}

先取字符串 再遍历字符串 赋值给新数组 返回新数组

三数之和

我自己写的

死于超出时间限制

三个for 排序后固定一个刷下面俩个 再固定一个接着刷

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);//排序
        List<List<Integer>> result = new ArrayList<>();
        for (int i = 0; i < nums.length-2; i++) {
            //防止下一个数和上一个数字相同
            if(i>0&&nums[i]==nums[i-1]){
                continue;//自己写的时候把下面俩循环都套了 然后发现还有个直接退出本次循环的语句
            }
            for (int j = i+1; j < nums.length-1; j++) {
                if(j>i+1&&nums[j]==nums[j-1]){
                    continue;
                }
                for (int k = j+1; k < nums.length; k++) {
                    if(k>j+1&&nums[k]==nums[k-1]){
                        continue;
                    }else if (nums[i]+nums[j]+nums[k]==0){
                        List<Integer> list = new ArrayList<>();
                        list.add(nums[i]);
                        list.add(nums[j]);
                        list.add(nums[k]);
                        result.add(list);
                    }
                }
            }
        }
        return result;
    }
}

大神代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);//排序,nums变成递增数组
        List<List<Integer>> res = new ArrayList<>();
        //k < nums.length - 2是为了保证后面还能存在两个数字
        for(int k = 0; k < nums.length - 2; k++){
            if(nums[k] > 0) break;//若nums[k]大于0,则后面的数字也是大于零(排序后是递增的)
            if(k > 0 && nums[k] == nums[k - 1]) continue;//nums[k]值重复了,去重
            int i = k + 1, j = nums.length - 1;//定义左右指针
            while(i < j){//if语句判断找到合适数字后返回此while语句
                int sum = nums[k] + nums[i] + nums[j];
                if(sum < 0){
                    while(i < j && nums[i] == nums[++i]);//左指针前进并去重
                } else if (sum > 0) {
                    while(i < j && nums[j] == nums[--j]);//右指针后退并去重
                } else {
                    res.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j])));
                    //nums[j]增大, nums[k]减小, 依旧可能满足三数之和为0,继续遍历去重                    
                    while(i < j && nums[i] == nums[++i]);//左指针前进并去重
                    while(i < j && nums[j] == nums[--j]);//右指针后退并去重
                }
            }
        }
        return res;
    }
}

说实话还有官方代码 懒得贴了 都是双指针 用法不同

另外,吐槽自己的代码好低效

整体思想

排序后 呈现升序 eg:-4 -3 -3 -2 -1 0 0 1 1 3 3 6

所以第一个数字一定不能大于0 如果第一个数字大于0那么结果一定不等于0

第二个for循环开启双指针 一个指向固定的第一个数字(-4)后方(-3) 一个指向最后的数字(6)

如果三个加一起的值<0 证明 前俩数加一起负数更大 左指针(-3)去重(-3)并右移(-2)(对比上面例子)

同理 如果三个加一起的值>0 证明 后面的数字更大 右指针去重左移

直到 找到合适的数组 存入

值得说明的是 存入后

其实写一个也可以 主要目的是排查中间是否有更多合适数字

因为例如[-4,-2,6] 后面还有[-4,0,4]这种

为什么写两个 因为不让用相同的数字 所以同时改变双指针效率更快

while(i < j && nums[i] == nums[++i]);//左指针前进并去重

while(i < j && nums[j] == nums[--j]);//右指针后退并去重

最接近的三数之和

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。

返回这三个数的和。

假定每组输入只存在恰好一个解。

 

示例 1:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
示例 2:

输入:nums = [0,0,0], target = 1
输出:0
 

提示:

3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104

哈哈,经典三个for循环 肯定是自己写的

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int sum=0;int temp=nums[0]+nums[1]+nums[2];
        for (int i = 0; i <nums.length-2; i++) {
            for (int j = i+1; j <nums.length-1; j++) {
                for (int k = j+1; k <nums.length; k++) {
                    sum=nums[i]+nums[j]+nums[k];
                    if(Math.abs(sum-target)<Math.abs(temp-target)){
                        temp=sum;
                    }
                }
            }
        }
        return temp;
    }
}

典中典大神代码

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);//排序
        int ans = nums[0] + nums[1] + nums[2];//设置初始对比值
        for(int i=0;i<nums.length;i++) {
            int start = i+1, end = nums.length - 1;//双指针替代俩for
            while(start < end) {//如果没重合
                int sum = nums[start] + nums[end] + nums[i];
                if(Math.abs(target - sum) < Math.abs(target - ans))//比绝对值
                    ans = sum;
                if(sum > target)//因为排序了 和比目标值大 证明后面的数字大 改右指针
                    end--;
                else if(sum < target)//同理 需要改左指针
                    start++;
                else
                    return ans;
            }
        }
        return ans;
    }
}

不用想 双指针一定比我那破三for查的快且效率高 对比上一个三数之和 没有去重要求 这个雀氏煎蛋

不过肯定还能再优化,例如去重

还是得学习大神代码

八股

String 类的常用方法都有那些?

equals() 比较字符串

trim() 去除字符串两边空白

split()根据括号内容分割字符串数组

indexof() 根据字符串查索引

replace()替换字符串

substring() 截字符串

charAt() 返回指定索引处的字符

getBytes() 返回字符串的 byte 类型数组。

length() 返回字符串长度。

toLowerCase() 将字符串转成小写字母。

toUpperCase() 将字符串转成大写字符。

抽象类必须要有抽象方法吗?

不一定,静态main方法输出也可以

普通类和抽象类有哪些区别?

普通类不能包含抽象方法,抽象类可以包含抽象方法。

抽象类不能直接实例化,普通类可以直接实例化。

抽象类能使用 final 修饰吗?

不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承

接口和抽象类有什么区别?

抽象类需要被继承,接口需要被实现

一个类可以有多个接口,但只能继承一个抽象类

抽象类可以有构造函数和main方法 接口不能

抽象类的方法可以被任意修饰符修饰,接口的方法只能用public

java 中 IO 流分为几种?

按功能来 是输入流 输出流

按类型来 是字节流 字符流

字节流以8位字节输出数据 字符流以16位字符输出数据

BIO、NIO、AIO 有什么区别?

BIO是同步阻塞IO 是常用的IO 特点简单方便 并发处理低

NIO是同步非阻塞IO 可以让客户端和服务器通过信道实现多路复用

AIO是NIO的升级版 是异步非阻塞IO 操作是以事件和回调机制

Files的常用方法都有哪些?

Files.exists():检测文件路径是否存在。

Files.createFile():创建文件。

Files.createDirectory():创建文件夹。

Files.delete():删除一个文件或目录。

Files.copy():复制文件。

Files.move():移动文件。

Files.size():查看文件个数。

Files.read():读取文件。

Files.write():写入文件。

rabbitMQ第二天

(PS:有点docker的底子直接去docker安装了 但是安装了半天 最后发现特别脑残,因为自己第一次安装容器时进去了,不知道用什么网址打开,就又安装了一次,之后就一直显示同命名容器已存在,请删除后重试,但是我试图进去又显示没有运行此容器,然后我就TM删了又装,装了又删,最后发现,重启docker容器就好了 tm..... 相信我,重启docker解决99%问题)

(附上大神链接https://huaweicloud.csdn.net/638db4f8dacf622b8df8ccb9.html?spm=1001.2101.3001.6650.9&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~activity-9-127265712-blog-128782579.pc_relevant_3mothn_strategy_and_data_recovery&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~activity-9-127265712-blog-128782579.pc_relevant_3mothn_strategy_and_data_recovery&utm_relevant_index=14)

如果超时了访问(https://blog.csdn.net/Lzxccas/article/details/112061753)

添加用户

docker进入容器
docker exec -it 容器ID /bin/bash
创建账号
rabbitmqctl add_user admin 123
设置用户角色
rabbitmqctl set_user_tags admin administrator
设置用户权限
set_permissions [-p <vhostpath>] <user> <conf> <write> <read>
rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
用户 user_admin 具有/vhost1 这个 virtual host 中所有资源的配置、写、读权限
查看当前用户和角色
rabbitmqctl list_users

简单队列

原理图

创建完maven项目 导入包

<!--指定 jdk 编译版本-->
<build>
 <plugins>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-compiler-plugin</artifactId>
 <configuration>
 <source>8</source>
 <target>8</target>
 </configuration>
 </plugin>
 </plugins>
</build>
<dependencies>
 <!--rabbitmq 依赖客户端-->
 <dependency>
 <groupId>com.rabbitmq</groupId>
 <artifactId>amqp-client</artifactId>
 <version>5.8.0</version>
 </dependency>
 <!--操作文件流的一个依赖-->
 <dependency>
 <groupId>commons-io</groupId>
 <artifactId>commons-io</artifactId>
 <version>2.6</version>
 </dependency>
</dependencies>

生产者发消息给队列 队列接收消息发送给消费者

消费者代码


import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

/**
 *生产者给队列发消息
 */
public class Producer {
    private final static String QUEUE_NAME = "hello";//队列名字
    public static void main(String[] args) throws Exception {
        //创建一个连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.179.130");//连接RMQ的IP
        factory.setUsername("admin");//账号
        factory.setPassword("admin");//密码
        //channel 实现了自动 close 接口 自动关闭 不需要显示关闭
        try(Connection connection = factory.newConnection(); //信道
            Channel channel = connection.createChannel()) {//队列
            /**
             * 生成一个队列
             * 1.队列名称 queue_name
             * 2.队列里面的消息是否持久化(磁盘) 默认消息存储在内存中
             * 3.该队列是否只供一个消费者进行消费 是否进行共享 true 可以多个消费者消费,false只能一个消费者消费
             * 4.是否自动删除 最后一个消费者端开连接以后 该队列是否自动删除 true 自动删除,false部自动删除
             * 5.其他参数
             */
            channel.queueDeclare(QUEUE_NAME,false,false,false,null);
            String message="hello world";//发消息 初次使用不考虑交换机
            /**
             * 发送一个消息
             * 1.发送到那个交换机 初次使用暂时不考虑所以写空字符串
             * 2.路由的 key 是哪个 队列名称
             * 3.其他的参数信息
             * 4.发送消息的消息体
             */
            channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
            System.out.println("消息发送完毕");
        }
    }
}

运行后发现rabbitmq的queues里面出现hello队列 有个ready待处理

消费者代码

import com.rabbitmq.client.*;

/**
 *消费者从队列接收消息
 */
public class Consumer {
    //队列名称
    private final static String QUEUE_NAME = "hello";

    //接收消息
    public static void main(String[] args) throws Exception {
        //创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.179.130");
        factory.setUsername("admin");
        factory.setPassword("admin");
        //建立新连接
        Connection connection = factory.newConnection();

        //连接创建信道
        //有信道可以发送和接收消息
        Channel channel = connection.createChannel();
        System.out.println("等待接收消息....");

        //推送的消息如何进行消费的接口回调
        //声明接收消息 consumerTag消费者标签 delivery交付
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            //消息本身有消息体 消息头等 因此获得消息体
            String message = new String(delivery.getBody());
            System.out.println(message);
        };
        //取消消费的一个回调接口 如在消费的时候队列被删除掉了
        CancelCallback cancelCallback = (consumerTag) -> {
            System.out.println("消息消费被中断");
        };
        /**
         * 消费者消费消息
         * 1.消费哪个队列
         * 2.消费成功之后是否要自动应答 true 代表自动应答 false 手动应答
         * 3.消费者未成功消费的回调
         * 4。消费者取消消费的回调
         */
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, cancelCallback);
    }
}

运行后发现 idea出现了hello world 后台消息队列存的信息发送出去了

工作队列

原理图

工作线程是竞争关系

遵循轮训分发(依次)

抽取工具类

抽取成一个until

public class RabbitMqUtils {
    //得到一个连接的 channel
    public static Channel getChannel() throws Exception{
        //创建连接工厂
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("192.168.179.130");
        factory.setUsername("admin");
        factory.setPassword("admin");
        //建立新连接
        Connection connection = factory.newConnection();
        //连接创建信道
        //有信道可以发送和接收消息
        Channel channel = connection.createChannel();
        return channel;
    }
}
工作线程代码

import com.atguigu.rabbitmq.utils.RabbitMqUtils;
import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;



/**
 *这是一个工作线程(相当于之前的消费者)
 */
public class Worker01 {
    //队列名称
    private static final String QUEUE_NAME = "hello";

    public static void main(String[] args) throws Exception {
        Channel channel = RabbitMqUtils.getChannel();
        //消息接收
        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String receivedMessage = new String(delivery.getBody());
            System.out.println("接收到消息:" + receivedMessage);
        };
        //消息接收被取消时 执行下面内容
        CancelCallback cancelCallback = (consumerTag) -> {
            System.out.println(consumerTag + "消费者取消消费接口回调逻辑");
        };
        System.out.println("C1 消费者启动等待消费......");
       //消费者消费信息
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, cancelCallback);
    }
}

在IDEA可以开启多个线程

生产者代码

import com.atguigu.rabbitmq.utils.RabbitMqUtils;
import com.rabbitmq.client.Channel;

import java.util.Scanner;

/**
 *生产者 发送大量的消息
 */
public class Task01 {
    //队列名字
    private static final String QUEUE_NAME="hello";

    //发送大量消息
    public static void main(String[] args) throws Exception {
        //生成队列
        try(Channel channel= RabbitMqUtils.getChannel();) {
            channel.queueDeclare(QUEUE_NAME,false,false,false,null);
            //从控制台当中接受信息
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNext()){
                String message = scanner.next();

                //交换机,队列名字,其他参数,字符串消息体
                channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
                System.out.println("发送消息完成:"+message);
            }
        }
    }
}

在控制台输入信息 被其余的工作线程截获

预期c1 aa cc c2 bb dd

消息应答

概念:

为了保证消息在发送过程中不丢失,rabbitmq 引入消息应答机制,

消息应答就是:消费者在接收到消息并且处理该消息之后,告诉 rabbitmq 它已经处理了,rabbitmq 可以把该消息删除了

自动应答:

这种模式需要在高吞吐量和数据传输安全性方面做权衡 要么多,要么安全

没有对传递的消息数量进行限制,有可能使得消费者这边由于接收太多还来不及处理的消息,导致这些消息的积压,最终使得内存耗尽,最终这些消费者线程被操作系统杀死

所以这种模式仅适用在消费者可以高效并以某种速率能够处理这些消息的情况下使用

手动应答方法:

A.Channel.basicAck(用于肯定确认)

RabbitMQ 已知道该消息并且成功的处理消息,可以将其丢弃了

B.Channel.basicNack(用于否定确认)

C.Channel.basicReject(用于否定确认)

与 Channel.basicNack 相比少一个参数

不处理该消息了直接拒绝,可以将其丢弃了

Multilple批量应答(不建议批量):

手动应答的好处是可以批量应答并且减少网络拥堵

multiple 的 true 和 false 代表不同意思

true 代表批量应答 channel 上未应答的消息

比如说 channel 上有传送 tag 的消息 5,6,7,8 当前 tag 是 8 那么此时

5-8 的这些还未应答的消息都会被确认收到消息应答

(可能会造成消息丢失)

false 同上面相比

只会应答 tag=8 的消息 5,6,7 这三个消息依然不会被确认收到消息应答

消息自动重新入队:

如果通道关闭或者连接丢失关闭 导致消息ACK未确认

RMQ就会将其消息重新排队

消息手动应答代码:

默认消息采用的是自动应答,所以我们要想实现消息消费过程中不丢失,需要把自动应答改

为手动应答

生产者:

import com.atguigu.rabbitmq.utils.RabbitMqUtils;
import com.rabbitmq.client.Channel;

import java.util.Scanner;

/**
 *消息在手动应答时不丢失
 * 放回队列重新消费
 */
public class Task2 {
    //队列名称
    public static final String TASK_QUEUE_NAME = "ack_queue";
    public static void main(String[] argv) throws Exception {
        //声明队列 队列名字 是否持久化 共享 自动删除 其他
        try (Channel channel = RabbitMqUtils.getChannel()) {
            channel.queueDeclare(TASK_QUEUE_NAME, false, false, false, null);
            //控制台输入
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入信息");
            while (sc.hasNext()) {
                String message = sc.nextLine();
                channel.basicPublish("", TASK_QUEUE_NAME, null, message.getBytes("UTF-8"));
                System.out.println("生产者发出消息" + message);
            }
        }
    }
}
消费者01:(处理快)

import com.atguigu.rabbitmq.utils.RabbitMqUtils;
import com.atguigu.rabbitmq.utils.SleepUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;

/**
 *消息在手动应答时不丢失
 *放回队列重新消费
 */
public class Work03 {
    //队列名称
    public static final String TASK_QUEUE_NAME = "ack_queue";
    public static void main(String[] args) throws Exception {
        //接收消息
        Channel channel = RabbitMqUtils.getChannel();
        System.out.println("C1 等待接收消息处理时间较短");

        //消息消费的时候如何处理消息
        DeliverCallback deliverCallback=(consumerTag, delivery)->{
            String message= new String(delivery.getBody(),"UTF-8");
            //沉睡1S
            SleepUtils.sleep(1);
            System.out.println("接收到消息:"+message);
            //手动应答
            /**
             * 1.消息标记 tag
             * 2.是否批量应答未应答消息
             */
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        };
        //采用手动应答
        boolean autoAck=false;
        channel.basicConsume(TASK_QUEUE_NAME,autoAck,deliverCallback,(consumerTag)->{
            System.out.println(consumerTag+"消费者取消消费接口回调逻辑");
        });
    }
}

消费者02:(处理慢) 假设宕机 慢处理的能否将消息放回

import com.atguigu.rabbitmq.utils.RabbitMqUtils;
import com.atguigu.rabbitmq.utils.SleepUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.DeliverCallback;

/**
 *消息在手动应答时不丢失
 *放回队列重新消费
 */
public class Work03 {
    //队列名称
    public static final String TASK_QUEUE_NAME = "ack_queue";
    public static void main(String[] args) throws Exception {
        //接收消息
        Channel channel = RabbitMqUtils.getChannel();
        System.out.println("C2 等待接收消息处理时间较长");

        //消息消费的时候如何处理消息
        DeliverCallback deliverCallback=(consumerTag, delivery)->{
            String message= new String(delivery.getBody(),"UTF-8");
            //沉睡1S
            SleepUtils.sleep(30);
            System.out.println("接收到消息:"+message);
            //手动应答
            /**
             * 1.消息标记 tag
             * 2.是否批量应答未应答消息
             */
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        };
        //采用手动应答
        boolean autoAck=false;
        channel.basicConsume(TASK_QUEUE_NAME,autoAck,deliverCallback,(consumerTag)->{
            System.out.println(consumerTag+"消费者取消消费接口回调逻辑");
        });
    }
}

演示:

生产者先发消息 启动两个消费者 然后发送信息,

其中c2等待30S 一旦C2丢失连接,信息会被C1接收

RabbitMQ持久化

队列持久化:

之前我们创建的队列都是非持久化的,rabbitmq 如果重启的化,该队列就会被删除掉,如果要队列实现持久化 需要在声明队列的时候把 durable 参数设置为持久化

但是需要注意的就是如果之前声明的队列不是持久化的,需要把原先队列先删除,或者重新创建一个持久化的队列,不然就会出现错误

就是在之前的第一个false变成true

boolean durable = true;//需要让queue进行持久化
            channel.queueDeclare(TASK_QUEUE_NAME, durable, false, false, null);

消息持久化:

队列持久化了消息也要持久化

可以看出 第三个位置出现MessageProperties.PERSISTENT_TEXT_PLAIN

将消息标记为持久化并不能完全保证不会丢失消息

while (sc.hasNext()) {
                String message = sc.nextLine();
                //设置生产者发送消息位持久化消息(要求保存在磁盘上)
                //保存到内容中
                channel.basicPublish("", TASK_QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes("UTF-8"));
                System.out.println("生产者发出消息" + message);
            }

不公平分发

刚开始学习时用的轮训分发,但是例如两个消费者 一个快 一个慢

很容易让快的消费者大部分时间处于空闲状态

为了避免这种情况,我们可以设置参数 channel.basicQos(1);

在消费者方改代码

     //不公平分发
        int preferctCount=1;
        channel.basicQos(1);//默认0 
        //采用手动应答
        boolean autoAck=false;
        channel.basicConsume(TASK_QUEUE_NAME,autoAck,deliverCallback,(consumerTag)->{
            System.out.println(consumerTag+"消费者取消消费接口回调逻辑");
        });

只有一方设置不公平分发不行 另一方或多方也要设置

预取值

prefetch=x x代表指定拿多少条

本身消息的发送就是异步发送的,所以在任何时候,channel 上肯定不止只有一个消息另外来自消费

者的手动确认本质上也是异步的。因此这里就存在一个未确认的消息缓冲区,因此希望开发人员能限制此

缓冲区的大小,以避免缓冲区里面无限制的未确认消息问题。这个时候就可以通过使用 basic.qos 方法设

置“预取计数”值来完成的。该值定义通道上允许的未确认消息的最大数量。一旦数量达到配置的数量,

RabbitMQ 将停止在通道上传递更多消息,除非至少有一个未处理的消息被确认

虽然自动应答传输消息速率是最佳的,但是,在这种情况下已传递但尚未处理的消息的数量也会增加,从而增加了消费者的 RAM 消耗(随机存取存储器)应该小心使用具有无限预处理

的自动确认模式或手动确认模式,

预取值为 1 是最保守的。当然这

将使吞吐量变得很低,特别是消费者连接延迟很严重的情况下,特别是在消费者连接等待时间较长的环境

中。对于大多数应用来说,稍微高一点的值将是最佳的。

 //不公平分发
//        int preferctCount=1;
        //但必须是堆积到队列才能显示
        int preferctCount=2;//这预取值是2 拿两条消息
        channel.basicQos(1);//默认0
        //采用手动应答

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值