这篇文章中不会介绍
sleep和wait, 会在其他的文章中介绍
1. stop
停止线程, 不推荐使用.
JDK中已经标识为@Deprecated, 因为太暴力, 无论线程运行到什么状态, 都会强制停止, 可能会导致数据的不一致, 并且不会抛出异常.
2. interrupt
中断线程
2.1 非阻塞状态的线程
相当于一个中断的标志位, 调用之后, 只是把这个标志位改成true.
可以通过interrupted()这个方法来判断中断状态.
也就是说, 单纯的调用这个interrupt()方法, 是不会使得线程的运行中断的, 如果要中断线程的运行, 可以通过这样的代码来控制
public void run(){
while(true){
if(Thread.currentThread().isInterrupted())
{
System.out.println("Interruted!");
break;
}
Thread.yield(); //这里可以是正常的线程执行操作
}
}
2.2 阻塞状态的线程
对于可取消的阻塞状态中的线程, 比如等待在这些函数上的线程, Thread.sleep(), Object.wait(), Thread.join(), 这个线程收到中断信号后, 会抛出InterruptedException, 同时会把中断状态置回为false.
理论上所有会throws InterruptedException的方法都是可以取消阻塞状态的.
对于取消阻塞状态中的线程,可以这样写代码
public void run(){
while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("Interruted!");
break;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Interruted When Sleep");
//设置中断状态,抛出异常后会清除中断标记位
Thread.currentThread().interrupt();
}
Thread.yield();//这里可以是正常的线程执行操作
}
}
sleep的中断比较容易, 但是wait方法如果被中断, 不一定会马上抛出异常, 如果获取不到锁对象, 就会继续等待, 知道获取之后才会抛出InterruptedException.
此外, interrupt()还可以在使用Lock对象的时候, 解决死锁的问题(可以参考Lock的lockInterruptibly()
方法)
3. suspend和resume
线程挂起(suspend)和继续执行(resume)
这两个方法都是Deprecated方法,不推荐使用。
原因在于,suspend不释放锁,因此如果suspend在synchronized块中执行的,并且也没有其他线程来执行resume方法, 这个线程将一直占有这把锁,造成死锁发生。
4. yield
让出CPU资源
这个让出只是一下, 执行完之后, 线程并不是变成等待状态, 而是从 "运行状态" 转换为 "就绪状态", 也就是说可能这个线程还是可能会马上抢占到CPU的资源
官方说是可用于debug和test, 基本找不到使用的场景...
5. join
等待其他线程结束
join的本质
while (isAlive()) {
wait(0);
}
详细的可以查看join的源码
public static void main(String[] args) throws Exception {
Thread r1 = new Thread(new MyThread());
r1.start();
r1.join();//等待r1线程执行完之后,才会继续执行下面的语句
System.out.println("主线程结束");
}
上面的代码, 主线程在执行r1.join()的时候就会判断r1.isAlive(), 如果r1线程还活着, 就wait(0)
既然是wait操作, 肯定会有锁对象. join方法是synchronized的, 所以调用这个方法的对象就是锁对象. 上面这个锁对象就是r1这个线程对象
同样, 既然是wait, 肯定会有对应的notify来唤醒这个wait
那么问题是谁在哪里调用了notify呢?
在join方法的javadoc中找到了解释:
Waits at most millis milliseconds for this thread to die. A timeout of 0 means to wait forever.
This implementation uses a loop of this.wait calls conditioned on this.isAlive. As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.
意思是在每个线程结束之后, 都有调用this.notifyAll(), 那么这个操作可以理解为是由JVM自动完成的动作. 上面的代码则会在r1这个线程结束之后, JVM自动调用this.notifyAll(), 这里的this相当于r1, 然后把所有等待r1这个锁对象的线程给唤醒.
所以javadoc中还给了我们一个建议,不要使用wait和notify/notifyAll在线程实例上。因为jvm会自己调用,有可能与你调用期望的结果不同。