IOTXING

记录技术学习之路

0%

背景

前两天一个朋友面试,遇到了一个题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.LinkedList;

public class Stack {
LinkedList list = new LinkedList();
public synchronized void push(Object x) {
synchronized(list) {
list.addLast( x );
notify();
}
}

public synchronized Object pop()
throws Exception {
synchronized(list) {
if( list.size() <= 0 ) {
wait();
}
return list.removeLast();
}
}
}
Read more »

Hashmap

1.hashmap的家族

1
2
public class HashMap<K, V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable

能够看出,hashmap是map的一个实现类

Read more »

一般来说一次IO操作包含两个步骤

  • 内核准备数据
  • 数据从内核拷贝到用户进程

常见的IO模型主要有以下几种

  • 阻塞IO
  • 非阻塞IO
  • 多路复用IO
  • 信号驱动IO
  • 异步IO
Read more »

tableSizeFor

1
2
3
4
5
6
7
8
9
private static final int tableSizeFor(int c) {
int n = c - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

该算法相当奇妙,目的是输入一个数字c,然后返回离它最近的且值大于它的2的n次幂,例如输入7,返回8,输入123,返回128。

首先定义一个变量n为c-1,至于为什么为c-1,之后会说到。

我们输入c=13来带入计算一下

1
2
3
4
5
6
7
1. n = c-1    //此时n =  12,二进制为1100
2. n |= n >>> 1; n >>> 1,也就是n右移一位,得到0110,然后再与1100或运算,得到1110,此时n=1110
3. n |= n >>> 2; 这里n右移两位,得到0011,然后或运算得到1111;到这里n已经全为1了,不管怎么或运算,都会是1111。因此下面的几个结果都是1111
4. n |= n >>> 4;
5. n |= n >>> 8;
6 n |= n >>> 16;
7. 这里进行计算,如果n大于MAXIMUM_CAPACITY,返回MAXIMUM_CAPACITY,否则返回n+1,n目前的值是1111,是奇数,而我们要得到的是2的n次方,因此需要加一计算,得到想要的结果

这里我们可以回头看上面的第一步,n = c-1,如果不执行c-1的话,我们加入c为16,那么二进制就是10000,经过一番操作之后,会得到最后的n为11111,然后加一就会变成100000,也就是32,而理论结果应该是16。

对于一个传进来的非0数字,从第一个1开始,右移一位,然后或运算,相当于第一位和第二位都变成了1,然后右移两位,变成了第一二三四位都变成了1,依次类推,一直右移1+2+4+8+16位,也就是最大右移了31位,最终再加一,就是2的32位

现象

在一次压测过程中,设置了500并发并且持续5分钟,在3分钟的时候,发现所有链接都关闭了,并且获取不到任何链接,出现以下的报错提示

image-20200511172738852

Read more »

Spring中的事务,主要有以下几个参数

  • value:事务名称
  • transactionManager:事务管理器
  • propagation:传播行为
  • isolation:隔离级别
  • timeout:超时时间,如果在超时时间内事务没有提交,则事务就会被终止(此处会有坑)
  • readOnly:是否只读事务(需要参考所用的数据源是否支持,如mysql支持只读事务)
  • rollbackFor:何时回滚
  • noRollbackFor:在遇到某些异常时,不回滚
Read more »

案发现场

在任务开始的时候,状态为INIT,然后需要等待定时器去取状态为INIT的任务,修改状态然后执行。但是在下午开始,突然发现INIT的任务一直处于INIT的状态,而定时器却是5s轮询一次,没有头绪,只能继续等,刚好当时在做别的事情,就没有在意。

吃过饭之后,看了下错误日志,看到了下面的内容

image-20200508203023740

通过输出,能够发现错误是因为事务锁一直在等待获取锁,处于卡主的状态

Read more »

之前使用的nginx伪装流量,后来发现是有问题的,很快就被封了。
之前的思路是,机器保留443端口,然后使用ssr去链接跳板机的443端口,如果是ssr协议,就转发到本地的ssr服务,如果是http请求,就返回对应的页面。
这么做存在一个漏洞,所有经过443端口的流量都会被探测到,如果检测到ssr的特征,就会直接导致机器的端口被封,连不上。而443和80又是被检测的高风险端口

Read more »

java中提供的线程池基本都是继承自ExecutorService,可以通过Executors来创建线程池。
java中提供了以下几种线程池,

  • newCachedThreadPool
  • newFixedThreadPool
  • newSingleThreadExecutor
  • newScheduledThreadPool

newFixedThreadPool

固定容量的线程池,除非某个线程被显式关闭,否则线程会一直存活。在执行任务的时候,如果线程池的线程都已经在工作状态了,新来的任务就会被加入等待队列,直到线程池中有线程执行完,或者出现异常被终止等情况,新的任务就会占据这个线程开始执行。

newCachedThreadPool

该线程池不能传入线程池大小,默认设定代销为Integer的MAX_VALUE。每个执行完的线程,会保留60s,如果60s内有新任务进来,则重复利用该线程去跑,如果超过60s,没被利用,则线程就会被销毁。如果长时间没有新任务进来,该线程池不消耗任何资源

newSingleThreadExecutor

只有一个线程的线程池,在线程挂了之后,会起一个新的线程来替代

newScheduledThreadPool

可以定期执行线程,或者是延迟一定时间后,执行

Read more »