Java多线程

1、多线程实现方式及区别 https://www.jianshu.com/p/f65ea68a4a7f      

由于java不能多继承可以实现多个接口,因此,在创建线程的时候尽量多考虑采用实现接口的形式;
线程创建之后调用start()方法开始运行,当调用wait(),join(),LockSupport.lock()方法线程会进入到WAITING状态,而同样的wait(long timeout),sleep(long),join(long),LockSupport.parkNanos(),LockSupport.parkUtil()增加了超时等待的功能,也就是调用这些方法后线程会进入TIMED_WAITING状态,当超时等待时间到达后,线程会切换到Runable的状态,另外当WAITING和TIMED _WAITING状态时可以通过Object.notify(),Object.notifyAll()方法使线程转换到Runable状态。当线程出现资源竞争时,即等待获取锁的时候,线程会进入到BLOCKED阻塞状态,当线程获取锁时,线程进入到Runable状态。线程运行结束后,线程进入到TERMINATED状态,状态转换可以说是线程的生命周期
实现方式:继承Thread类  or  实现Runnable接口
将Runnable对应的实现类放入线程中开启
线程五大状态:创建、就绪、阻塞、运行、死亡
Thread.yield()线程礼让  礼让不一定成功
由于多个线程共享一段存储空间,会存在冲突的问题,所以加入了锁机制synchronized,当一个线程获得了一个对象的排它锁,其他线程需要等待,使用后释放锁即可


线程间协作通信
通信是指线程之间以何种机制来交换信息,主要有两种:共享内存和消息传递   java内存模型是共享内存的并发模型,线程之间主要通过读-写共享变量来完成隐式通信
在java程序中所有实例域,静态域和数组元素都是放在堆内存中 (所有线程均可访问到,是可以共享的)


2、多线程怎么做同步   ReentrantLock     synchronized
在while循环里使用wait的目的,是在线程被唤醒的前后都持续检查条件是否被满足
notify()唤醒等待的线程,如果监视器种只有一个等待线程,使用notify()可以唤醒。但是如果有多条线程notify()是随机唤醒其中一条线程,与之对应的就是notifyAll()就是唤醒所有等待的线程


3、线程死锁、死锁产生的必要条件
死锁产生的原因:多个进程在运行过程中对同一个资源进行竞争,导致处于僵持状态,双方都无法继续推进 这种情况叫做死锁
死锁产生的条件:
互斥条件——进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用
占有且等待——当进程因请求资源而阻塞时,对已获得的资源保持不放  
不可剥夺条件——进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放    
循环等待条件——在发生死锁时,必然存在一个进程--资源的环形链

4、如何避免死锁
加锁顺序:线程按照相同的顺序加锁。
加锁时限,线程获取锁的过程中限制一定的时间,如果给定时间内获取不到,就算了,别勉强自己。这需要用到Lock的一些API
避免一个线程同时获得多个锁;
避免一个线程在锁内部占有多个资源,尽量保证每个锁只占用一个资源;
尝试使用定时锁,使用lock.tryLock(timeOut),当超时等待时当前线程不会阻塞;
对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况
Jstack命令——用来检测死锁

5、jvm 内部主数据存储 https://blog.csdn.net/qq_31024823/article/details/84140546
4整  2浮  1字  1布
jvm虚拟机组成:虚拟机栈、堆、程序计数器、方法区、本地方法栈
堆是用来存储对象本身和数组的
栈是用来存储方法中的局部变量(非静态变量、函数形参)
方法区可存储的内容有:类的全路径名、类的直接超类的权全限定名、类的访问修饰符、类的类型(类或接口)、类的直接接口全限定名的有序列表、常量池(字段,方法信息,静态变量,类型引用(class))等
虚拟机栈是为执行Java方法服务的,而本地方法栈是为执行本地方法服务的
程序计数器当前线程所执行的字节码的行号指示器,在程序运行过程中,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、异常处理、线程恢复等基础功能都需要依赖计数器完成




6、jvm内存回收  https://blog.csdn.net/yubujian_l/article/details/80804708
引用计数法
可达性分析算法:当一个对象到 GC Roots 没有任何的引用链相连时(从 GC Roots 到这个对象不可达)时,证明此对象不可用  筛选的条件是此对象是否有必要执行finalize()方法
垃圾回收算法:1、 标记-清除算法 2、复制算法(新生代回收算法) 3、标记整理算法(老年代回收算法)  4、分代收集算法

7、java反射及什么时候使用
反射就是动态加载对象,并对对象进行剖析。
使用场景一:不能明确接口调用哪个函数,需要根据传入的参数在运行时决定。
使用场景二:不能明确传入函数的参数类型,需要在运行时处理任意对象。

8、spring注解加载javabean过程 https://www.cnblogs.com/wyq178/p/11415877.html


9、切面编程AOP ump
这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

10、为什么保证线程安全  怎么保证线程安全


11、java多态
多态是针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法
多态允许添加更多类型的子类实现功能扩展,却不需要修改父类代码
多态分为编译时多态和运行时多态  编译时多态通过重载方式实现,运行时多态是通过方法的覆盖实现的
父类对象只能执行那些在父类中声明、被子类覆盖了的子类方法,不能执行子类增加的成员方法



12、异常的分类(Throwable、Error、Exception)
检查性异常:用户错误引起的异常,程序员无法预见
运行时异常:可能被避免的异常,运行时异常可以在编译时被忽略(数组越界、空指针、找不到类、算数异常)
throw主动抛出异常 throw new ***Exception  用于方法中的抛出异常
throws:用来声明一个方法可能产生的所有异常

13、静态代理和动态代理
通过静态代理可以实现除了对象能实现的方法外其他的方法

14、lambda表达式
一个接口里面只有唯一一个抽象方法,那么他就是函数式接口,对于函数式接口可以通过lambda表达式来创建该接口的对象
result =a->Sout(a)


15、内存泄露  是什么 以及产生的原因
jvm有垃圾回收机制。jvm使用引用计数法和可达性分析算法来判断一个对象是否是不再被引用的对象,对于这种情况,针对代码实现方式上的差别,可能会导致误认为对象还在被引用而没有进行垃圾回收,造成内存泄露
比如:
静态集合类:长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收
数据库连接、IO连接、网络连接:访问数据库或者请求网络连接时,如果不进行关闭,那么会造成大量对象无法被回收,造成内存泄露
变量不合理的作用域:变量使用完成后,如果没有及时地把对象设置为null,很有可能导致内存泄漏的发生
内部类持有外部类:内部类持有外部类的对象,尽管外部类不再被使用,外部类的对象也没有被垃圾回收

通常我们可以借助MAT、LeakCanary等工具来检测应用程序是否存在内存泄漏。
另外尽量使用静态内部类

 

posted @ 2020-11-20 18:00  stnnnn123  阅读(80)  评论(0)    收藏  举报