线程的start方法和run方法有什么区别?
- start方法用于启动一个新的线程,线程启动后会去执行run方法,这会新建一个线程
- run方法定义了线程要执行的任务,如果直接调用则会在当前线程中执行,相当于普通方法,不会新建线程
线程的创建方式有哪些?
- 继承Thread类,实现run方法
- 实现Runnable接口,实现run方法
- 实现 Callable 接口和call方法,并使用 FutureTask调用;类似Runnable接口,但是可以返回结果和抛出异常
- 使用线程池创建,此处涉及到ThreadFactory,可以自定义线程的创建过程
线程的生命周期、线程的状态转换
如何中断线程?
线程中断和结束,原则上应该由线程自己判断,不应由其他线程强制中断,其他线程可以发出请求,决定权还是线程本身。
- 调用线程的interrupt()方法,并不会立即终止线程,而是设置线程的中断标志,线程将正常运行。当线程在阻塞等待,比如调用sleep方法、join方法时,这些方法会抛出InterruptedException异常,并清除中断标志。如果线程不在阻塞状态,那么中断标志会被设置,线程可以在后续的代码中检查这个标志,并采取相应的行动。 所以在比如调用sleep方法中,要对InterruptedException异常进行处理,再次调用interrupt()方法来设置中断标志。
- 使用一个volatile变量,在其他线程修改变量值后,当前线程监听值的变化,进行下一步处理,停止、中断、或正常运行其他逻辑。
- 使用AtomicBoolean原子类,原理同volatile变量。
interrupt、interrupted、isInterrupted的区别
interrupt:将当前线程的中断标志位设置位true
isInterrupted:返回当前线程的中断标志位
interrupted:返回当前线程的中断标志位,将当前线程的中断标志位设置位false
线程的等待和唤醒机制
- 使用Object类的wait和notify方法,需要注意,使用这两个方法时,需要先获取锁,否则会抛出异常,且notify在wait后,防止一直等待。
- 使用Lock锁的Condition的await和signal,也需要先获取Lock后再调用这两个方法,否则会抛出异常,类似Object类的的wait和notify方法,signal在await后,防止一直等待。
- LockSupport的park和unpark(Thread thread)方法来实现线程的阻塞和唤醒操作,**区别在于:**无需先获取锁、无需先等待再唤醒(先发许可证permit,后续调用park无需等待,相当于闸机,一人一开),permit不会累计,连续调用只能发证一个,park会消耗一个permit,两个方法也需要成对使用。底层调用的是Unsafe内的native方法。