进程和线程的关系:
每一个进程对应一个JVM实例,多个线程共享JVM里的堆
JAVA采用单线程编程模型,程序会自动创建主线程
主线程可以创建子线程,原则上要后于子线程完成执行
Thread中的Start和run的区别
调用start()方法会创建一个新的子线程并启动
run()方法只是Thread的一个普通方法的调用
Thread和Runnable有什么关系
Thread实现了Runnable接口的类,使得run支持多线程
因为类的单一继承原则,推荐多使用Runnable接口
如何实现处理线程的返回值
主线程等待法,当线程多,代码多,不能精准控制
t.join(); 阻塞当前线程以等待子线程处理完毕
通过Callable接口实现:通过FutureTask Or线程池获取
线程的状态:
新建(New):创建后尚未启动的线程的状态
运行(Runnable):包含Running和Ready
无限期等待(Waiting):不会被分配CPU执行时间,需要显示被唤醒
没有设置时间参数Object.wait() Thread.join() LockSupport.park()
限期等待(time Waiting):在一定时间后会由系统自动唤醒
阻塞(Blocked):等待获取排他锁
结束(Terminated):已终止的线程
sleep和wait的区别:
基本的差别:
(1)sleep是Thread类的方法,wait是Object类中定义的方法
(2)sleep()方法可以在任何地方使用
(3)wait()方法只能在synchronized方法或synchronized块中使用
只有获取锁才能去释放锁
最主要的本质区别:
(1)Thread.sleep只会让出CPU,不会导致锁行为的改变
(2)Object.wait不仅让出CPU,还会释放以及占有的同步资源
notify和notifyAll的区别:
(1)notifyAll会让处于等待池的线程全部进入锁池去竞争获取锁的机会
(2)notify之后随机取一个
两个概念
锁池EntryList 等待池WaitSet
锁池的本质:
假设线程A已经拥有了某个对象的锁,而其它线程B、C要调用这个对象的某个synchronized方法,由于B、C线程在进入对象的synchronized方法之前必须先获得该对象锁的拥有权,而恰好该对象的锁目前被线程A占用,此时B、C线程就会阻塞,进入一个地方去等待锁的释放,这个地方便是该对象的锁池
等待池:
假设线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁,同时线程A就进入到了该对象的等待池中,进入到等待池中的线程不会去竞争该对象的锁。
二、 yield()方法
当调用Thread.yield()函数时,会给线程调度器一个当前线程愿意让出CPU使用的暗示,但是线程调度器可能会忽视这个暗示。(不会让出锁)
如何中断线程
调用interrupt(),通知线程应该中断了
(1)如果线程处于被阻塞状态,那么线程将立即退出被阻塞状态,并抛出一个InterruptedException异常
sleep、wait
(2)如果线程处于正常活动状态,那么会将该线程的中断标志设置为true。被设置中断标志的线程将会继续正常运行,不受影响
需要被调用的线程配合中断
(1)在正常运行任务时,经常检查本线程的中断标志,如果被设置了中断标志就自行停止线程。
(2)如果线程处于正常活动状态,那么会将线程的中断标志设置为true。被是指中断标志的现场将检修正常运行,不受影响