多线程相关知识点

一 线程的生命周期和状态

 

 


  线程创建之后它将处于 NEW(新建) 状态,调用 start() 方法后开始运行,线程这时候处于 READY(可运行) 状态。可运行状态的线程获得了 CPU 时间片(timeslice)后就处于 RUNNING(运行) 状态

二 什么是死锁?如何避免死锁?
多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。称为死锁
1一次性申请所有资源
2申请不到,主动释放占有的资源
3按序申请资源,反序释放资源

三 sleep() 方法和 wait() 方法区别和共同点?
sleep() 方法没有释放锁,而 wait() 方法释放了锁
wait() 通常被用于线程间交互/通信,sleep() 通常被用于暂停执行

四 start()方法和run()方法的区别

new 一个 Thread,线程进入了新建状态。调用 start()方法,会启动一个线程并使线程进入了就绪状态,

直接执行 run() 方法,会把 run() 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它

五 synchronized
1 操作系统实现线程之间的切换时需要从用户态转换到内核态,这个状态之间的转换需要相对比较长的时间,时间成本相对较高。
2 Java 6 之后 Java 官方对从 JVM 层面对 synchronized 较大优化,所以非极端场景使用 synchronized 可不考虑开销问题
3 synchronized 关键字的三种使用方式
1)修饰实例方法,会给当前实例对象加锁
2)修饰静态方法,会给当前类加锁并且作用于此类的所有实例对象
3)修饰代码块,取决于synchronized()括号中的参数
4 synchronized关键字不能修饰构造方法,因为构造方法本身就是线程安全的
5 synchronized原理: 同步语句块的实现使用的是 monitorenter(监控输入) 和 monitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。
当执行 monitorenter 指令时,线程试图获取锁也就是获取 对象监视器 monitor 的持有权。
每个对象都内置了一个ObjectMonitor对象,monitor是C++实现的

注意:尽量不要使用 synchronized(String a) 因为 JVM 中,字符串常量池具有缓存功能!
synchronized(class)类似修饰静态方法,也会给类和所有实例加锁

六 volatile
1 多线性需保证原子性,可见性,有序性
2 volatile 关键字可以保证,可见性和一定程度的有序性(volatile 可以禁止 JVM 的指令重排),但是无法保证原子性
3 因为volatile无法保证原子性所以使用是必须满足:1)对变量的写操作不依赖于当前值 2)该变量没有包含在具有其他变量的不变式中

七 ThreadLocal
1 ThreadLocal 可以让每一个线程都有自己的专属本地变量
2 原理:最终的变量是放在了当前线程的 ThreadLocalMap 中,并不是存在 ThreadLocal 上,
ThreadLocal 可以理解为只是ThreadLocalMap 的封装,传递了变量值。 ThrealLocal 类中可以通过Thread.currentThread()获取到当前线程对象后,
直接通过getMap(Thread t)可以访问到该线程的ThreadLocalMap对象。
每个Thread中都具备一个ThreadLocalMap,而ThreadLocalMap可以存储以ThreadLocal为 key ,Object 对象为 value 的键值对。
3 ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用,而 value 是强引用。所以,如果 ThreadLocal 没有被外部强引用的情况下,
在垃圾回收的时候,key 会被清理掉,而 value 不会被清理掉。使用完 ThreadLocal方法后 最好手动调用remove()方法

 

原文地址:https://www.cnblogs.com/yueguangshi/p/15033102.html