问:线程有哪些状态?

- 新建(new):创建后尚未启动的线程的状态(新创建的线程但还没有调用start方法)
- 运行(Runnable):包含Running和Ready(Running线程位于可运行线程中,等待调度选中获取CPU使用权,处于Ready状态的线程位于线程池中,等待调度选中,选中获取CPU时间后变为Running状态)
- 无限期等待(Waiting):不会被分配CPU执行时间,需要显式唤醒(notify、notifyAll),以下3个方法会让线程陷入无限期等待状态:
- 没有设置Timeout参数的Object.wait()方法
- 没有设置Timeout参数的Thread.join()方法
- LockSupport.park()方法
- 限期等待(Timed Waiting):在一定时间后会由系统自动唤醒(也不会分配CPU执行时间)以下方法会让线程进入限期等待:
- Thread.sleep()方法
- 设置了Timeout参数的Object.wait()方法
- 设置了Timeout参数的Thread.join()方法
- LockSupport.parkNanos()方法
- LockSupport.parkUntil()方法
- 阻塞(Blocked):等待获取排他锁(如synchronized同步代码块或方法会出现此状态)
- 结束(Terminated):已终止线程的状态,线程已经结束执行(结束状态的线程再调用start方法会抛出java.lang.IllegalThreadStateException异常)
问:sleep和wait的区别?
- sleep是Thread类的方法,wait是Object类的方法
- sleep方法是可以在任何方法使用
- wait方法只能在synchronized方法或者synchronized块中使用(因为只有获取锁了才能释放锁)
最主要的本质区别:
- Thread.sleep只会让出CPU,不会导致锁行为的改变
- Object.wait不仅让出CPU,还会释放已经占有的同步资源锁
Thread.java中的

Object.java中的

1package interview.thread; 2 3/** 4 * wait和sleep的区别 5 * @Author: cctv 6 * @Date: 2019/5/17 11:49 7 */ 8public class WaitSleepDemo { 9 public static void main(String[] args) { 10 final Object lock = new Object(); 11 new Thread(() -> { 12 System.out.println("thread A is waiting to get lock"); 13 synchronized (lock) { 14 try { 15 System.out.println("thread A get lock"); 16 // 先等B运行起来再到下一步 17 Thread.sleep(20); 18 System.out.println("thread A do wait method"); 19 // wait让出CPU和锁 B会抢到锁执行B后再执行A 20// lock.wait(1000); 21 22 // sleep不会让出锁 A执行完了之后再执行B 23 Thread.sleep(1000); 24 System.out.println("thread A is done"); 25 } catch (InterruptedException e) { 26 e.printStackTrace(); 27 } 28 } 29 }).start(); 30 31 // 先启动A拿到锁,再让B也运行 32 try { 33 Thread.sleep(10); 34 } catch (InterruptedException e) { 35 e.printStackTrace(); 36 } 37 new Thread(() -> { 38 System.out.println("thread B is waiting to get lock"); 39 synchronized (lock) { 40 try { 41 System.out.println("thread B get lock"); 42 System.out.println("thread B do wait method"); 43 Thread.sleep(10); 44 System.out.println("thread B is done"); 45 } catch (InterruptedException e) { 46 e.printStackTrace(); 47 } 48 } 49 }).start(); 50 51 52 } 53}
sleep结果:
wait结果:
问:notify和notifyAll的区别?
首先了解2个概念:
- 锁池EntryList(一个锁资源被占用之后其他其他线程想要获取锁就进入了阻塞状态,在一个地方等待锁的释放,这个地方就是锁池)
- 等待池WaitSet(线程调用某对象的wait方法之后旧进入等待状态,进入等待池中,进入等待吃的线程不会去竞争该对象的锁)
notifyAll会让所有处于等待池的线程全部进入锁池去竞争获取锁的机会
notify是随机选择一个处于等待池的线程进入锁池去竞争获取锁的机会
问:yiled的含义?
当调用Thread.yield()函数时,会给线程调度器一个当前线程愿意让出CPU使用的暗示,但是线程调度器可能会忽略这个暗示。
yield并不会让出当前占用的锁
问:如何中断线程?
-
已被抛弃的方法:
- 通过调用stop()方法停止线程(这种方法太过暴力,而且是不安全的。突然调用stop停止了线程,导致线程的一些清理工作无法完成,而且会释放锁,可能导致数据不同步的问题)
- 通过调用suspend()和resume()方法(原因和stop类似)
-
目前使用的方法:
- 调用interrupt(),通知线程应该中断了
- 如果线程处于被阻塞状态,那么线程将立刻退出被阻塞状态,并抛出一个InterruptedException异常
- 如果线程处于正常活动状态,那么会将该线程的中断标志设置为true。被设置中断标志的线程将继续正常运行,不受影响
- 需要被调用的线程配合中断:
- 在阻塞阻塞线程里,处理InterruptedException异常,并在catch里做好相关清理工作
- 在正常运行任务时,经常检查本线程的中断标志位(Thread.currentThread().isInterrupted()方法判断),如果被设置了中断标志就自行停止线程
测试:
1package interview.thread; 2 3/** 4 * 中断线程demo 5 * 6 * @Author: cctv 7 * @Date: 2019/5/20 10:26 8 */ 9public class InterruptDemo { 10 public static void main(String[] args) throws InterruptedException { 11 Runnable interruptTask = new Runnable() { 12 @Override 13 public void run() { 14 int i = 0; 15 Thread t = Thread.currentThread(); 16// 加上注释看阻塞状态的处理 去掉注释看工作状态的处理 17// try { 18 while (!t.isInterrupted()) { 19// Thread.sleep(100); 20 i++; 21 System.out.println(t.getName() + "(" + t.getState() + ") loop " + i); 22 } 23 System.out.println(t.getName() + "(" + t.getState() + ") Thread isInterrupted is true. loop is" + i); 24// } catch (InterruptedException e) { 25// System.out.println(t.getName() + "(" + t.getState() + ") catch InterruptedException. loop is " + i); 26// } 27 } 28 }; 29 Thread t1 = new Thread(interruptTask, "t1"); 30 System.out.println(t1.getName() + "(" + t1.getState() + ") is new"); 31 32 t1.start(); 33 System.out.println(t1.getName() + "(" + t1.getState() + ") is started"); 34 35 Thread.sleep(300); 36 t1.interrupt(); 37 System.out.println(t1.getName() + "(" + t1.getState() + ") is interrupted"); 38 39 Thread.sleep(300); 40 System.out.println(t1.getName() + "(" + t1.getState() + ") is terminated"); 41 } 42}

