前言
本文主要讲述线程实现、线程状态、线程优先级、守护线程、线程常用API以及线程中断和停止。
一、线程实现
1、继承Thread类,继承后重写run方法,调用start()方法就可以跑起来了
2、实现Runnable接口,实现后一定要重写run方法,然后传参给Thread类的构造函数创建出Thread对象,然后调用start(0方法
3、实现Callable接口,与Runnable相比,执行完run方法后有返回值,其它一致
二、线程状态
线程共有5种状态:
1、创建状态:我们创建出一个线程对象后,它就进入了创建状态
2、运行状态:我们调用了start()方法后,线程进入了运行状态,此时它可能正在运行,也可能正等待CPU分配时间片
3、等待状态:此时线程在等待其他线程的唤醒或是等待一定时间后由系统唤醒,这又可以分为:
无限等待状态:线程不会被CPU分配时间片直到其他线程的唤醒,常见用例:
未设置Timeout参数的Object.wait()
未设置Timeout参数的Thread.join()
限期等待状态:线程会在一定时间后被系统自动唤醒,常见用例:
设置了Timeout参数的Object.wait()
设置了Timeout参数的Thread.join()
Thread.sleep()方法
4、阻塞状态:此时线程正在等待获取一个排他锁。
5、结束状态:线程执行完run方法后进入结束状态
三、线程优先级
Java线程的优先级共有10种,默认优先级为5,最大为10,最小为1。线程的优先级并不意味着一定能先得到CPU的时间片分配,只是让其更容易被系统选择分配。值得我们注意的是,java线程是通过映射到系统的原生线程上实现的,所以线程调度最终还是取决于操作系统,比如windows线程优先级只有7种,因此java的几个不同优先级映射到windows中就会出现相同的情况。
四、守护线程
守护线程也被称为后台线程,如要设置必须在创建状态也就是start前设置,守护线程是可以继承的,如果当前所有的用户线程都退出了,那么守护线程也会退出。守护线程的常见实例就是JVM的GC线程。
五、线程中断
我们调用interupt()方法使得线程进入中断状态,这时线程内部的中断信号会被设置为true。我们要在线程的执行体中通过线程的中断检查事件(isInterrupted())判断有无进入中断状态,一般而言我们会用while(Thread.currentThread().isInterrupted()){}的语法。
六、线程常用API
1、设置线程本身属性
编号 | 方法 | 说明 |
1 | public final void setName(String name) | 设置线程名称 |
2 | public final void setPriority(int priority) | 设置线程优先级,默认为5 |
3 | public final void setDaemon(boolean on) | 将线程标记为守护线程或是用户线程 |
2、 其他常用方法
编号 | 方法 | 说明 |
1 | public void start() | 调用它使线程进入运行状态 |
2 | public void run() | 线程运行的任务 |
3 | public final void join();public final void join(long millisec) | 主线程等待该线程运行完毕 |
4 | public void interrupt() | 设置线程中断信号为true |
5 | public final native boolean isAlive() | 判断线程是否处于运行状态 |
6 | public static Thread currentThread() | 返回当前的对象实例 |
7 | public static native void sleep(long millisec) | 当前线程交出CPU时间片但不释放对象锁,一般用于线程暂停 |
8 | public static native void yield() | 暂停当前执行的线程,线程进入限期等待状态 |
七、 常见问题
1、start()方法与run()方法有什么不同?
start()方法用于启动线程,使线程进入运行状态,而run()方法只是实现了线程任务的一个方法,单独运行run()方法只是让主线程去执行了一个普通方法,并没有创建新线程。
2、sleep()方法和wait()方法有什么不同?
①、sleep()方法只是阻塞了线程,并未释放锁,wait()方法释放了锁;②、sleep()是Thread类下的方法,wait()方法是Object类的;3、sleep()方法一般用于暂停线程,wait()通常用于线程间的交互和通信
3、yield()和sleep()有什么不同?
①、yield()方法执行后线程只是释放了当前的时间片,随时可以获取时间片重新运行,sleep则是进入等待状态,需要一定时间后才能重获时间片运行;2、yield()方法只会将CPU时间片获取机会给优先级相同或更高的线程,而sleep()方法则是一视同仁,任何线程都有机会获取时间片;3、sleep()必须声明InterruptedException而yield不必。
4、继承Thread类和实现Runnable接口有什么不同?
①我们都知道java只能单继承,而可以实现多个接口,实现Runnable后可以继承其他的类;②、实现Runnable接口,接口中的方法可以被其他线程共享。