多线程与高并发学习笔记(1)
1、什么是程序、进程、线程、协程?
程序就是安装在电脑上的.exe等的可执行文件。当执行了.exe文件后就是电脑中的一个进程,进程中有一个个小的执行单元叫做线程。
一个程序里不同的执行路径叫做线程。
2、run()和start()方法的区别?
run()方法执行: run()方法执行结果:
start()方法执行: start()方法执行结果:
run()方法的执行是:先走main函数,再走run()方法,直到run()方法走完,继续走main()方法。
start()方法的执行是:main()方法和run()方法同时运行。
3、面试题:启动线程的三种方式?
一、Thread 二、Runnable 三、线程池new ExecutorsCachedThread()
4、sleep()、yield()和join()?
sleep()方法:让程序睡眠
yield()方法:让出一下cpu进入等待队列,下一次还有可能执行。
join()方法:将一个线程加入到另外一个线程中。t1.join()
5、线程的状态?
new ==> runnable ==> running ==> terminated
6、synchronized关键字?
为什么要上锁?多个线程对同一个资源访问的时候需要用到锁
https://blog.csdn.net/scdn_cp/article/details/86491792
这三种方式是一样的
7、同步方法和非同步方法是否可以同时调用?
可以,因为非同步方法没加锁。
8、面试题:模拟银行账户,对业务写方法加锁,对业务读方法不加锁,行不行?
可以。这种叫做脏读。
9、synchronized锁是否是重入锁?
是。在一个类中的两个synchronized方法,方法A和方法B,方法A种调用方法B是可以的,因为先执行方法A获取到这个类的锁,
当执行方法A中的方法B的时候,发现获取的这个类的锁是同一个,继续执行方法B。所以叫可重入锁。
再举个反例。假设父类A有个synchronized方法m,子类B重写了父类synchronized方法m,并调用了super.m(),如果synchronized
不可重入,那么父子类之间就会形成死锁,这是不可能的。
重入锁实现可重入性原理或机制是:每一个锁关联一个线程持有者和计数器,当计数器为 0 时表示该锁没有被任何线程持有,
那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为 1;
此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;
当线程退出同步代码块时,计数器会递减,如果计数器为 0,则释放该锁。
10、异常和锁
程序中如果出现异常,锁会被释放。
11、synchronized底层实现
synchronized早期实现是重量级的,都是要找操作系统申请锁。
后来的改造:
锁升级:我就是厕所所长
第一步:synchronized(object) markword 记录这个线程ID还没上锁,叫偏向锁。
第二步:如果有线程争用:升级为自旋锁(就是一直申请资源)
第三步:自旋十次之后,如果还是这把锁,升级为重量级锁,去操作系统里面去申请锁。
自旋锁和os锁:
执行时间长,线程多的用os锁。执行时间短,且线程数比较少用自旋锁。
12、synchronized锁对象不能是String常量、Integer等
因为如果一个字符串常量锁一个类库,另外一个程序也用相同的字符串去锁定一个类库,可能造成执行多余的代码。
Integer里面做了一个索引,只要变换了值就做了一个新对象。
13、Object为空能不能当作锁对象?
不能。
14、操作系统和内核
操作系统内核可以访问应用程序,叫做操作系统内核态;
应用程序只能访问应用程序,叫做应用程序内核态。