容易忘记的知识点收集

1、

如果虚拟机栈不支持动态扩展,那么将会抛出StackOverFlow异常。如果支持动态扩展,那么这个栈会请求再扩展部分空间。当然内存不是无穷的,如果频繁的扩展内存,以至于无法再继续扩展了,这时候会抛出OutOfMemory异常。除此之外,堆得空间也是有限的。由于创建的对象都是要在堆中分配内存,那么如果堆中空间不足,没有足够的内存空间用来给新的对象分配内存,这时候也会抛出OutOfMemory异常。

2、

对于select语句,在解析查询之前,服务器会先检查查询缓存(Query Cache),如果能够在其中找到对应的查询,服务器就不必再执行查询解析、优化和执行的整个过程,而是直接返回查询缓存中的结果集。(来源:《高性能MySQL》P3)

3、

Java表达式1/0、1.0/0.0的值分别是什么?第一个表达式会产生一个运行时除以零异常(它会终止程序,因为这个值是未定义的);第二个表达式的值是Infinity(无穷大)

4、

关于整型加法溢出:

int a = 2147483647; 
System.out.println(a); 
int b = a + 1;
System.out.println(b);//整型溢出

简单的说,就是用字节的最高位表示符号的正负,0代表正,1代表负;但是这个符号位也会参与运算,java的int是4个字节,每个字节8位,所以int的最大值用二进制表示就是:

01111111 11111111 11111111 11111111;

将这个值加一时,从右往左一直进位,结果是:

10000000 00000000 00000000 00000000,

注意,最高位为1,表示负数,本来这个结果在原码里代表-0,但是补码消除了消除了+0和-0的冗余和歧义,使0只用一个表达方式就是:

00000000 00000000 00000000 00000000

反正放着“10000000 00000000 00000000 00000000”不用白不用,所以就用这个结果把补码的表示范围扩大一位,使其表达为最小值,而且这个值能满足运算的结果表示,即(-2147483647) + (-1)等等结果确实是这个值;比如,如果用反码,最小值是-2147483647,因为用的是补码,所以这个值不用白不用,不让它表示0,那就让它表示-2147483648(-2147483647 + (-1))吧

5、

查看端口被占用情况:netstat -nao | findstr 8080

taskkill /pid xxxx /f(xxxx代表占用8080端口的线程)

6、

JMM(Java Memory Model),是一种基于计算机内存模型(定义了共享内存系统中多线程程序读写操作行为的规范),屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能保证效果一致的机制及规范。保证共享内存的原子性、可见性、有序性。

7、

原子性:对共享内存的操作必须是要么全部执行直到执行结束,且中间过程不能被任何外部因素打断,要么就不执行。

有序性:程序的执行顺序按照代码顺序执行,在单线程环境下,程序的执行都是有序的,但是在多线程环境下,JMM 为了性能优化,编译器和处理器会对指令进行重排,程序的执行会变成无序。

可见性:多线程操作共享内存时,执行结果能够及时的同步到共享内存,确保其他线程对此结果及时可见。

8、

Java中如何获取到线程dump文件?

9、

synchronized和ReentrantLock的区别?

10、CAS

CAS,全称为Compare and Set,即比较-设置。假设有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,才会将内存值修改为B并返回true,否则什么都不做并返回false。当然CAS一定要volatile变量配合,这样才能保证每次拿到的变量是主内存中最新的那个值,否则旧的预期值A对某条线程来说,永远是一个不会变的值A,只要某次CAS操作失败,永远都不可能成功。

CAS的缺点:
1、CPU开销较大
在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很大的压力。
2、不能保证代码块的原子性
CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用Synchronized了。

11、

volatile不能保证原子性

volatile 变量写入并不保证线程安全,也不具备原子性。原因是在执行内存屏障之前,不同 CPU 依旧可以对同一个缓存行持有,一个 CPU 对同一个缓存行的修改不能让另一个 CPU 及时感知,因此出现并发冲突。线程安全还是需要用锁来保障,锁能有效的让 CPU 在同一个时刻独占某个缓存行,执行完并释放锁后,其他CPU才能访问该缓存行。锁既能保证线程安全又能保证内存可见,而 volatile 只能保证内存可见。

12、

ReentrantLock和synchronized比较

①、ReentrantLock和synchronized都是独占锁,只允许线程互斥的访问临界区。但是实现上两者不同:synchronized加锁解锁的过程是隐式的,用户不用手动操作,优点是操作简单,但显得不够灵活。一般并发场景使用synchronized的就够了;ReentrantLock需要手动加锁和解锁,且解锁的操作尽量要放在finally代码块中,保证线程正确释放锁。ReentrantLock操作较为复杂,但是因为可以手动控制加锁和解锁过程,在复杂的并发场景中能派上用场。
②、ReentrantLock和synchronized都是可重入的。synchronized因为可重入因此可以放在被递归执行的方法上,且不用担心线程最后能否正确释放锁;而ReentrantLock在重入时要却确保重复获取锁的次数必须和重复释放锁的次数一样,否则可能导致其他线程无法获得该锁。

13、

下面输出是什么?

        int a = 10;
        int b = 4;
        int c = a/b;
        int d = c*a*b++;
        System.out.println(d);
        System.out.println(5|7);
        System.out.println(10|4);
        System.out.println(a|b);    

 14、终端查看端口被占用情况及杀死占用该端口的进程

  ①、查看该端口xxxx被占用情况:“netstat -ano|findstr xxxx”

  ②、根据得出来的进程号yyyy查看具体的程序名称:"tasklist|findstr yyyy"

  ③、强制、递归 删除本程序及其子进程:"taskkill -f -t -im zzzz"(例如taskkill -f -t -im QQ.exe)

posted @ 2019-10-24 23:39  CodeCorner  阅读(141)  评论(0)    收藏  举报