/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return {@code true} (as specified by {@link Collection#add}) */ publicbooleanadd(E e){ final ReentrantLock lock = this.lock;//重入锁 lock.lock();//加锁啦 try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1);//拷贝新数组 newElements[len] = e; setArray(newElements);//将引用指向新数组 1 returntrue; } finally { lock.unlock();//解锁啦 } }
缓存 I/O 的缺点: 数据在传输过程中需要在应用程序地址空间和内核进行多次数据拷贝操作,这些数据拷贝操作所带来的 CPU 以及内存开销是非常大的。
二 IO模式
刚才说了,对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说,当一个read操作发生时,它会经历两个阶段: \1. 等待数据准备 (Waiting for the data to be ready) \2. 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)
在说明synchronous IO和asynchronous IO的区别之前,需要先给出两者的定义。POSIX的定义是这样子的: - A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes; - An asynchronous I/O operation does not cause the requesting process to be blocked;
int epoll_create(int size);//创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); intepoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
1. int epoll_create(int size); 创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大,这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值,参数size并不是限制了epoll所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。 当创建好epoll句柄后,它就会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。
2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 函数是对指定描述符fd执行op操作。 - epfd:是epoll_create()的返回值。 - op:表示op操作,用三个宏来表示:添加EPOLL_CTL_ADD,删除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。分别添加、删除和修改对fd的监听事件。 - fd:是需要监听的fd(文件描述符) - epoll_event:是告诉内核需要监听什么事,struct epoll_event结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
structepoll_event { __uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ };
3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); 等待epfd上的io事件,最多返回maxevents个事件。 参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。
ET模式: 如果我们在第1步将RFD添加到epoll描述符的时候使用了EPOLLET标志,那么在第5步调用epoll_wait(2)之后将有可能会挂起,因为剩余的数据还存在于文件的输入缓冲区内,而且数据发出端还在等待一个针对已经发出数据的反馈信息。只有在监视的文件句柄上发生了某个事件的时候 ET 工作模式才会汇报事件。因此在第5步的时候,调用者可能会放弃等待仍在存在于文件输入缓冲区内的剩余数据。
netstat -an会打印系统当前网络链接状态,而grep ESTABLISHED 提取出已建立连接的信息。 然后wc -l统计 最终返回的数字就是当前所有80端口的已建立连接的总数。
1
netstat -nat||grep ESTABLISHED|wc
可查看所有建立连接的详细记录
19、输出每个ip的连接数,以及总的各个状态的连接数
1
netstat -n | awk '/^tcp/ {n=split($(NF-1),array,":");if(n<=2)++S[array[(1)]];else++S[array[(4)]];++s[$NF];++N} END {for(a in S){printf("%-20s %s\n", a, S[a]);++I}printf("%-20s %s\n","TOTAL_IP",I);for(a in s) printf("%-20s %s\n",a, s[a]);printf("%-20s %s\n","TOTAL_LINK",N);}
对于字符串类型,可以指定索引前缀长度(且对于 BLOB/TEXT 前缀长度参数是必须的),在 InnoDB 表中其前缀长度最长是 767 bytes,且参数 M 是用 bytes 计量的。所以太长的字符串,建立 B+Tree 索引浪费比较大,这时候用手动模拟 HASH 索引是个方法,不过这种方式对字符串无法灵活的使用前缀方式查询(例如 LIKE 这类的操作)。
联合索引
单列索引指的是在表上为某一个字段建立的索引,一般索引的创建选择整型或者较小的定长字符串将更有利于效率的提升。联合索引指的是多个字段按照一定顺序组织的索引。以索引 (name, city, gender) 为例,其首先是按照 name 字段顺序组织的,当 name 字段的值相同时(如 Bush),其按照 city 字段顺序组织,当 city 字段值相同时,其按照 gender 字段组织。由于联合索引上通过多个列构建索引,有时候我们可以将需要频繁查询的字段加到联合索引里面,譬如经常需要根据 name 查找 age 我们可以建一个 name 和 age 的联合索引。
常见的条件联合包括了 WHERE 条件联合与 ORDER BY 条件联合;所谓 WHERE 条件联合指的是,对于 WHERE 条件中的等值条件,其字段使用与联合索引的字段一致(顺序可以不一致)。
ORDER BY 联合指的是如果 ORDER BY 后面的字段是联合索引覆盖 where 条件之后的一个字段,由于索引已经处于有序状态,MySQL 就会直接从索引上读取有序的数据,然后在磁盘上读取数据之后按照该顺序组织数据,从而减少了对磁盘数据进行排序的操作。即对于未覆盖 ORDER BY 的查询,其有一项 Creating sort index,即为磁盘数据进行排序的耗时最高;对于覆盖 ORDER BY 的查询,其就不需要进行排序,而其耗时主要体现在从磁盘上拉取数据的过程。
以 (name, city, interest) 三个字段联合的索引为例,如果查询条件为 where name='Bush'; 那么就只需要根据 B+树定位到 name 字段第一个 Bush 所在的值,然后顺序扫描后续数据,直到找到第一个不为 Bush 的数据即可,扫描过程中将该索引片的数据 id 记录下来,最后根据 id 查询聚簇索引获取结果集。同理对于查询条件为 where name='Bush' and city='Chicago'; 的查询,MySQL 可以根据联合索引直接定位到中间灰色部分的索引片,然后获取该索引片的数据 id,最后根据 id 查询聚簇索引获取结果集。
由此我们可以得出联合索引前缀的注意点:
无法跨越字段使用联合索引,如 where name='Bush' and interest='baseball';,对于该查询,name 字段是可以使用联合索引的第一个字段过滤大部分数据的,但是对于 interest 字段,其无法通过 B+ 树的特性直接定位第三个字段的索引片数据,比如这里的 baseball 可能分散在了第二条和第七条数据之中。最终,interest 字段其实进行的是覆盖索引扫描。
对于非等值条件,如 >、<、!= 等,联合索引前缀对于索引片的过滤只能到第一个使用非等值条件的字段为止,后续字段虽然在联合索引上也无法参与索引片的过滤。这里比如 where name='Bush' and city>'Chicago' and interest='baseball';,对于该查询条件,首先可以根据 name 字段过滤索引片中第一个字段的非 Bush 的数据,然后根据联合索引的第二个字段定位到索引片的 Chicago 位置,由于其是非等值条件,这里 MySQL 就会从定位的 Chicago 往下顺序扫描,由于 interest 字段是可能分散在索引第三个字段的任何位置的,因而第三个字段无法参与索引片的过滤。
# 使用索引 A>5 AND A<10 - 最左前缀匹配 A=5 AND B>6 - 最左前缀匹配 A=5 AND B=6 AND C=7 - 全列匹配 A=5 AND B IN (2,3) AND C>5 - 最左前缀匹配,填坑
# 不能使用索引 B>5 - 没有包含最左前缀 B=6 AND C=7 - 没有包含最左前缀
# 使用部分索引 A>5 AND B=2 - 使用索引 A 列 A=5 AND B>6 AND C=2 - 使用索引的 A 和 B 列 复制代码
使用索引对结果进行排序,需要索引的顺序和 ORDER BY 子句中的顺序一致,并且所有列的升降序一致(ASC/DESC)。如果查询连接了多个表,只有在 ORDER BY 的列引用的是第一个表才可以(需要按序 JOIN)。
1 2 3 4 5 6 7 8 9 10 11 12 13
# 使用索引排序 ORDER BY A - 最左前缀匹配 WHERE A=5 ORDER BY B,C - 最左前缀匹配 WHERE A=5 ORDER BY B DESC - 最左前缀匹配 WHERE A>5 ORDER BY A,B - 最左前缀匹配
# 不能使用索引排序 WHERE A=5 ORDER BY B DESC,C ASC - 升降序不一致 WHERE A=5 ORDER BY B,D - D 不在索引中 WHERE A=5 ORDER BY C - 没有包含最左前缀 WHERE A>5 ORDER BY B,C - 第一列是范围条件,无法使用 BC 排序 WHERE A=5 AND B IN(1, 2) ORDER BY C - B 也是范围条件,无法用 C 排序 复制代码
like 前缀
对于 like 前缀,其是指在使用 like 查询时,如果使用的表达式为 first_name like 'rMq%';那么其是可以用到 first_name 字段的索引的。但是对于 first_name like '%Chu%';,其就无法使用 first_name 的索引。对于 like 前缀,MySQL 底层实际上是使用了一个补全策略来使用索引的,比如这里 first_name like 'rMq%';,MySQL 会将其补全为两条数据:rMqAAAAA 和 rMqzzzzz,后面补全部分的长度为当前字段的最大长度。在使用索引查询时,MySQL 就使用这两条数据进行索引定位,最后需要的结果集就是这两个定位点的中间部分的数据。如下是使用 like 前缀的一个示意图:
select count(*) as cnt, first_name as perf from actor group by perf ORDER BY cnt desc limit 10; -- 0 select count(*) as cnt, left(first_name, 2) as perf from actor group by perf ORDER BY cnt desc limit 10; -- 2 select count(*) as cnt, left(first_name, 3) as perf from actor group by perf ORDER BY cnt desc limit 10; -- 3 select count(*) as cnt, left(first_name, 4) as perf from actor group by perf ORDER BY cnt desc limit 10; -- 4 复制代码
void master_thread() ( loop: for (int i =0; i <10; i++){ do thing once per second sleep 1 second if necessary } do things once per ten seconds goto loop; } 复制代码
publicintnumOfBitToChange(int m, int n){ int result = m ^ n; int count = 0; int flag = 1; while(flag != 0) { if((result & flag) != 0) { count ++; } flag << 1; } return count; }