什么是线程
CPU调度的最基本单位。
线程创建与运行
线程的创建有三种方式
-
通过继承Thread类覆盖run方法
-
实现runnable接口
-
实现Callable接口,此方式能够获取任务执行完毕的返回结果
线程通知与等待
-
wait方法
当一个线程调用共享变量的wait函数时,该线程会阻塞挂起并释放共享变量的锁. 线程的唤醒需由其他线程通过调用共享变量的notify方法或notifyAll方法。但有可能存在虚假唤醒的情况,所以程代码的一般写法都是如下,以保障程序的健壮性.
synchroized(shareVariable){
while(quque.size() == MAX_SIZE){
// 阻塞挂起
shareVariable.await();
}
}
2. wait(long timeout)方法
线程调用共享变量的wait(long timeout),在指定timeout时间内如果没其他线程调用共享变量的notify或notifyAll方法,该线程将会因为超时而自动唤醒。需要注意的是 timeout=0 和不传入参数时方法功能时相同的,timeout=-1将会抛出IllegalArgumentsException异常。
3. notify()方法
该方法会随机唤醒一个因调用共享变量wait方法而挂起的线程,唤起的线程会继续开始和其他线程争抢共享变量的监视器锁.
4. notifyAll()方法
该方法则会唤醒全部因调用共享变量wait方法而挂起的线程,让所有的线程继续争抢共享变量的监视器锁。
5. Thread的join方法
A线程调用了B线程的join方法时,A线程将会阻塞挂起,等待B线程任务结束唤醒它继续执行。
6. Thread的sleep方法
线程调用此方法之后会进入休眠状态,出让CPU执行权,只有等到指定睡眠时间过后,才会继续参与CPU调度。需要注意的是:该线程锁持有的共享变量监视器锁资源仍然是不释放的。
7. yield方法
线程会出让CPU执行权,并处于就绪状态,等待CPU调度器分配下一轮时间片。
8. 线程中断
线程的中断并不是终止线程的执行,而是通过设置中断标志位,让被中断的线程根据中断标志位自行处理。
-
interrupt()
对线程进行中断操作,只是设置了线程中断的标志位,线程仍然能够继续执行。需要注意的是对于阻塞挂起的线程如果调用了中断操作将会抛出IntteruptedException异常
-
isInterrpted()
检测线程是否被中断(线程是否设置了中断标志位)
-
interrupted()
检测线程是否被中断,此方法与isInterrpt()不同之处在于:interrupted为Thread的静态方法、调用之后会清除中断标志位,isInterrpt调用之后并不会清楚中断标志位。
应用场景:
线程为了等待某些资源调用sleep方法让其进行阻塞挂起30s,但是等待的资源早在2s内就完成了。如果一直等到30s再返回有点浪费时间,这时就可以调用该线程的interrupt方法,抛出异常让线程恢复到激活状态。
上下文切换
当线程将CPU分配的时间片用完之后,会处于就绪状态等待和其他线程继续竞争CPU资源来进行下次的执行,此步骤就是上下文切换。为了保证线程下次分配到CPU时间片继续执行,所以线程上下文切换的时候需要保存执行现场。
守护线程和用户线程
主线程执行完毕后, 如果存在用户线程,那么JVM进程是不会结束。
主线程执行完毕后,如果只存在守护线程,那么JVM进程会立马结束。
主线程也是用户线程