每日一句

如果你执意追赶我的幻影,迟早会被真正的我战胜。

https://www.ylcoder.top/post/1649241412

概述

工作队列(又称工作队列)的次要思维是防止立刻执行资源密集型工作,咱们能够在安顿工作之后再执行。

咱们把工作封装为音讯并将其发送到队列,在后盾运行的工作过程将弹出工作,并最终执行作业。

当有多个工作线程时,这些工作线程将一起解决这些工作。

轮询散发音讯

在这里案例中咱们会启动两个工作线程,一个音讯发送线程

源码:https://github.com/yltrcc/rabbitmq-demo/tree/master/demo2/src/main/java/com/yltrcc/demo

不偏心散发

轮询散发在某些场景下并不是很好。

例子:比方有两个消费者在解决工作,其中有1个消费者1解决工作十分快,另外一个消费者2处理速度很慢。

这个时候采纳轮询散发,速度快的消费者1很大部分工夫处于闲暇状态,解决慢的消费者2始终在解决。

这种状况下其实不太好,然而RabbitMQ不晓得,它仍然很偏心的进行散发。

为了防止这种状况,咱们能够设置参数

它的意思是:这个工作我还没有解决完或者我还没有应答你,你先别调配给我,我目前只能解决一个工作,而后RabbitMQ就会把任务分配给没有那么忙的那个闲暇消费者。

当然如果所有的消费者都没有实现手上的工作,队列还在不停的增加新工作,队列有可能就会遇到队列被撑满的状况,这个时候就只能增加新的worker或者扭转其余存储工作的策略。

预取值

自身音讯的发送就是异步发送的,所以在任何时候,channel 上必定不止只有一个音讯另外来自消费者的手动确认实质上也是异步的。

因而这里就存在一个未确认的音讯缓冲区,因而心愿开发人员能限度此缓冲区的大小,以防止缓冲区外面无限度的未确认音讯问题

这个时候就能够通过应用 basic.qos 办法设置“预取计数”值来实现的。该值定义通道上容许的未确认音讯的最大数量。一旦数量达到配置的数量,
RabbitMQ 将进行在通道上传递更多音讯,除非至多有一个未解决的音讯被确认。

例如,假如在通道上有未确认的音讯 5、6、7,8,并且通道的预取计数设置为 4,此时RabbitMQ 将不会在该通道上再传递任何音讯,除非至多有一个未应答的音讯被 ack。

比方说 tag=6 这个音讯刚刚被确认 ACK,RabbitMQ 将会感知这个状况到并再发送一条音讯。

音讯应答和 QoS 预取值对用户吞吐量有重大影响。通常,减少预取将进步向消费者传递音讯的速度。

面试题

String和StringBuilder、StringBuffer的区别?

String是只读字符串,String 的底层是一个 char[] 通过final关键字进行润饰,所以说它的内容是不能被扭转的。
StringBuilder是Java 5中引入的,它和StringBuffer的办法完全相同,
区别在于它是在单线程环境下应用的,因为它的所有方面都没有被synchronized润饰,因而它的效率也比StringBuffer要高。

字符串的+操作其本质是创立了StringBuilder对象进行append操作,而后将拼接后的StringBuilder对象用toString办法解决成String对象,
这一点能够用javap -c Test.class命令取得class文件对应的JVM字节码指令就能够看出。

Redis 怎么查看所有的key?

# 列出所有的keyredis> keys *# 列出匹配的keyredis>keys apple*1) apple12) apple2

LeetCode 3 无反复字符的最长子串

题目链接

https://leetcode-cn.com/problems/two-sum/

题目形容

给定一个字符串 s ,请你找出其中不含有反复字符的 最长子串 的长度。

示例

示例 1:

输出: s = "abcabcbb"输入: 3 解释: 因为无反复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输出: s = "bbbbb"输入: 1解释: 因为无反复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输出: s = "pwwkew"输入: 3解释: 因为无反复字符的最长子串是 "wke",所以其长度为 3。     请留神,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

提醒

0 <= s.length <= 5 * (10 ^ 4)s 由英文字母、数字、符号和空格组成

题解

题解一:滑动窗口

用一个例子思考如何在较优的工夫复杂度内通过本题。

以示例一中的字符串abcabcbb为例,找出从每一个字符开始的,不蕴含反复字符的最长子串,那么其中最长的那个字符串即为答案。

对于示例一中的字符串,咱们列举出这些后果,其中括号中示意选中的字符以及最长的字符串:

  • 以 (a)bcabcbb 开始的最长字符串为 (abc)abcbb;
  • 以 a(b)cabcbb 开始的最长字符串为 a(bca)bcbb;
  • 以 ab(c)abcbb 开始的最长字符串为 ab(cab)cbb;
  • 以 abc(a)bcbb 开始的最长字符串为 abc(abc)bb;
  • 以 abca(b)cbb 开始的最长字符串为 abca(bc)bb;
  • 以 abcab(c)bb 开始的最长字符串为 abcab(cb)b;
  • 以 abcabc(b)b 开始的最长字符串为 abcabc(b)b;
  • 以 abcabcb(b) 开始的最长字符串为 abcabcb(b);

如果咱们顺次递增地枚举子串的起始地位,那么子串的完结地位也是递增的!这里的起因在于,假如咱们抉择字符串中的第 k 个字符作为起始地位,并且失去了不蕴含反复字符的最长子串的完结地位为 r_k。

那么当咱们抉择第 k+1 个字符作为起始地位时,首先从 k+1 到 r_k的字符显然是不反复的,并且因为少了本来的第 k 个字符,咱们能够尝试持续增大 r_k,直到右侧呈现了反复字符为止。

这样一来,咱们就能够应用「滑动窗口」来解决这个问题了:

  • 咱们应用两个指针示意字符串中的某个子串(或窗口)的左右边界,其中左指针代表着上文中「枚举子串的起始地位」,而右指针即为上文中的 r_k;
  • 在每一步的操作中,咱们会将左指针向右挪动一格,示意 咱们开始枚举下一个字符作为起始地位,而后咱们能够一直地向右挪动右指针,但须要保障这两个指针对应的子串中没有反复的字符。在挪动完结后,这个子串就对应着 以左指针开始的,不蕴含反复字符的最长子串。咱们记录下这个子串的长度;
  • 在枚举完结后,咱们找到的最长的子串的长度即为答案。

判断反复字符

在下面的流程中,咱们还须要应用一种数据结构来判断 是否有反复的字符,罕用的数据结构为哈希汇合(即 C++ 中的 std::unordered_set,Java 中的 HashSet,Python 中的 set, JavaScript 中的 Set)。在左指针向右挪动的时候,咱们从哈希汇合中移除一个字符,在右指针向右挪动的时候,咱们往哈希汇合中增加一个字符。

class Solution {    public int lengthOfLongestSubstring(String s) {        // 哈希汇合,记录每个字符是否呈现过        Set<Character> occ = new HashSet<Character>();        int n = s.length();        // 右指针,初始值为 -1,相当于咱们在字符串的左边界的左侧,还没有开始挪动        int rk = -1, ans = 0;        for (int i = 0; i < n; ++i) {            if (i != 0) {                // 左指针向右挪动一格,移除一个字符                occ.remove(s.charAt(i - 1));            }            while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {                // 一直地挪动右指针                occ.add(s.charAt(rk + 1));                ++rk;            }            // 第 i 到 rk 个字符是一个极长的无反复字符子串            ans = Math.max(ans, rk - i + 1);        }        return ans;    }}

复杂度剖析

  • 工夫复杂度:O(N)O(N),其中 NN 是字符串的长度。左指针和右指针别离会遍历整个字符串一次。
  • 空间复杂度:O(∣∣),其中 示意字符集(即字符串中能够呈现的字符),∣∣ 示意字符集的大小。在本题中没有明确阐明字符集,因而能够默认为所有 ASCII 码在[0,128) 内的字符,即 ∣∣=128。咱们须要用到哈希汇合来存储呈现过的字符,而字符最多有 ∣∣ 个,因而空间复杂度为O(∣∣)。
你好,我是yltrcc,日常分享技术点滴,欢送关注我:ylcoder