线程状态
线程有6种状态,一个线程实例可以通过调用getState()
方法来获取线程当前的状态
New:
新创建线程——当用new操作符创建一个线程时,线程还没有开始运行,当前线程的状态为New
Runnable
Java线程中将将就绪(Rready)和运行中(Running)两种状态统称为Runnable
一旦调用start()
方法线程就处于Runnable状态,一个Runnable的线程可能正在运行也可能还没有运行,这取决于CPU的调度
Ready
就绪状态只是说你资格运行,调度程序没有挑选到你,你就永远是就绪状态
- 调用线程的start()方法,此线程进入就绪状态。
- 当前线程sleep()方法结束,其他线程join()结束,等待用户输入完毕,某个线程拿到对象锁,这些线程也将进入就绪状态。
- 当前线程时间片用完了,调用当前线程的yield()方法,当前线程进入就绪状态。
- 锁池里的线程拿到对象锁后,进入就绪状态
Running
线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这是线程进入运行状态的唯一一种方式。
Blocked
当线程处于被阻塞或等待状态时,它不运行任何代码且消耗最少的资源。当一个线程试图获取一个内部的对象锁,而该锁被其他线程持有,则该线程进入阻塞状态,当所有其他线程释放该锁,并且线程调度器允许本线程持有它的时候,该线程变成非阻塞状态。
Waiting
处于等待状态的线程不会被分配CPU执行时间,它们要等待被显式地唤醒,否则会处于无限期等待的状态。在调用wait()
的或join()
方法,或是等待Lock或Condition时,当前线程进入等待状态。而notify()
和notifyAll()
的作用,则是唤醒当前对象上的等待线程。
Timed waiting
调用带有超时参数的方法,如sleep,wait,wait,await,tryLock方法。调用它们导致线程进入计时等待状态。这一状态将一直保持到计时期满或接收到通知。
Terminated
线程因如下两个原因之一被终止:
- run方法的正常退出而自然死亡
- 因为一个没有捕获的异常终止了run方法而意外死亡
一般希望线程自然结束run方法而终止,不建议调用被摒弃的stop方法
一旦线程进入终止状态,就不能再调用start方法了。
线程状态转换
线程属性
线程优先级
- 每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。
- Java 线程的优先级是一个整数,其取值范围是 1(Thread.MIN_PRIORITY )- 10 (Thread.MAX_PRIORITY )
- 默认线程优先级为5(NORM_PRIORITY)
- 优先级高调度的可能性大,但不代表高优先级一定在低优先级之前调度
守护线程
可以通过调用
t.setDaemon(true);
将线程转换为守护线程。
-
守护线程唯一的作用是为其它线程提供服务
-
当只剩下守护线程时,虚拟机就退出了
-
守护线程不应该去访问固有资源,如文件,数据库,因为随时可能发生中断
线程创建
Thread
可以通过继承Thread类,重写run
方法,该方法是新线程的入口点
run()
可以调用其他方法,使用其他类,并声明变量,就像主线程一样
最后创建一个该类的实例,调用start()
开始执行
下面是Tread类中的一些常用方法:
public void start(); //使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
public final void setName(String name); //设置线程名称。
public final void setPriority(int priority); //设置线程的优先级。
public final void setDaemon(boolean on); //将该线程标记为守护线程或用户线程。
public final void join(long millisec); //等待这个线程终止再继续执行,时间最长为 millis 毫秒。
public final boolean isAlive(); //测试线程是否处于活动状态。
//静态方法
public static void yield(); //将该线程由Running转换为Ready,和其他线程竞争
public static void sleep(long millisec); //让当前正在执行的线程休眠
public static boolean holdsLock(Object x); //当前线程在指定的对象上保持监视器锁时,返回 true。
public static Thread currentThread(); //返回对当前正在执行的线程对象的引用。
Runnable接口
创建一个线程,最简单的方法是创建一个实现 Runnable 接口的类,实现其中的run
方法。
new一个Thread对象,将接口作为参数传递进去
Runnable是函数式接口,最好使用lamda表达式,降低耦合性
Thread(Runnable target,String threadName);
,调用start()
开始执行
Callable&Future
Callable与Runnable类似,但是有返回值。Callable接口是一个参数化的类型,只有一个call
方法:
public interface Callable<V> {
V call() throws Exception;
}
类型参数是返回值类型,例如Callable<Integer>
,表示该线程最终会返回一个Integer对象。
Callable一般情况下是配合ExecutorService来使用的,在ExecutorService接口中声明了若干个 submit
方法的重载版本:
Future submit(Callable task);
Future submit(Runnable task);
Future submit(Runnable task, T result);
Future 类位于 java.util.concurrent 包下,它是一个接口:
public interface Future {
boolean cancel(boolean mayInterruptIfRunning); //取消任务
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get