线程的生命周期有新建、就绪、运行、阻塞、死亡
新建
当Thread对象被new出来,但未调用start方法时,此时进入新建状态(未取得执行权)
就绪
Thread对象调用了start方法,线程进入就绪状态,也就是说,这个时候线程正在等待队列中等待CPU分配时间片
运行
这个时候线程已经获得了时间片,并执行run方法中的内容,除非线程自身放弃时间片或有更高权重的线程加入,否则线程将一直运行到结束或时间片结束
阻塞
线程在执行run方法期间由于某些原因让出了CPU并暂停自己的执行,即进入阻塞状态,阻塞后进入就绪状态
1)等待阻塞,调用了wait方法,JVM会把线程放入等待池中
2)同步阻塞,当线程获取同步锁时,竞争失败,JVM会把线程放入锁池中
3)其他阻塞,线程调用了sleep、join方法时,或者其他I/O操作时,当sleep状态超时,join等待线程终止,I/O操作完成时,又会进入就绪状态
死亡
当线程执行完run方法或被其他线程杀死,那么进入死亡状态,进入该状态后不会再进入就绪状态
使用线程池
背景:
在面向对象编程中,对象的创建和销毁是非常耗时的,因为JVM需要跟踪对象并进行垃圾回收,尤其像线程这类非常宝贵的资源,这也是池化技术的产生背景。
采用线程池的好处
1、线程复用,减少资源创建和销毁的时间和资源
2、统一管理,线程池可以对线程进行监控和分配
3、提高响应速度
什么是线程安全
指多线程访问一个对象,不用考虑线程之间的执行交替,也不需要额外的同步机制,在调用方的其他协调操作下,仍能获取正确的值
volatile关键字原理
目前赞无权威答案,百度上较多的说法是JVM在运行程序时,为了加快运行速度,并非从内存中直接读取变量值,而是从寄存器中或CPU缓存中获取,当某个变量被volatile修饰时,线程A试图修改该变量,会先将缓存中的变量值清除,从内存中重新读取。后续B线程读取这个变量时,会向总线发送消息,A收到消息后,将新值传给B,最后将新值写入内存。
volatile关键字总结
本质上就是告诉JVM,我修饰的这个变量是不靠谱的,你必须每次从内存中读取
volatile与synchronized的区别
前者只能修饰变量,后者可修饰变量和方法
前者是非阻塞的,后者是阻塞的
前者仅仅保证了可见性,而后者保证了原子性和可见性
synchronized的粒度
当修饰成员方法时,this对象即作为锁的对象
当修饰代码块时,若无指定变量作为锁,则this为锁
当修饰静态方法时,class作为锁对象
