1.线程常用API
- public void start()
开始执行一个线程,调用run()方法。注意同一个线程不可以多次调用start()方法. - public static Thread currentThread()
获取当前线程对象 - public String getName()
获取线程名字 - public Thread.State getState()
获取线程状态 - public void interrupt()
中断线程 - public void join() /public void join(long millis)
等待线程结束 / 等待线程结束时间最长为millis毫秒 - public void setDaemon(boolean on)
将线程标记为用户线程(普通线程)或者守护线程 - public static void sleep(long millis)
让正在执行的线程休眠millis毫秒 - public static void yield()
暂停当前线程,执行其他线程
2.线程的生命周期
线程的主要状态共有六种,分别是:
1. NEW(新建状态)
2. RUNNABLE(就绪状态)
3. BLOCKED(阻塞状态)
4. WAITING(等待状态)
5. TIMED_WAITING(等待指定时间状态)
6. TERMINATED(退出状态)
我在网上看到过一个线程状态的转换图,很直观:
PS:图片出自csdn博客Allen Iverson,图片转载需要注明出处。
简单解释一下,我们使用构造方法获得线程对象的时候,线程进入新建状态,调用线程start()方法,线程进入就绪状态,系统分配资源时,进入运行状态,调用sleep()方法,线程进入等待状态,调用wait()方法,线程进入阻塞状态,当wait()时间结束或者join()线程结束,线程会回到就绪状态,当run()方法结束,线程进入死亡状态。
3.守护线程和用户线程
线程分为两种,一种是用户线程(User Thread),另一种是守护线程(Daemon Thread)。
两种线程使用方法都是差不多的,区别在于结束方式,因为守护线程是为用户线程提供服务的,所以守护线程随着用户线程的结束而结束的,当用户线程进入死亡状态,当jvm里面没有用户线程了,守护线程自动结束运行,也进入死亡状态。
关于守护线程有三个地方需要注意:
- 必须先调用setDaemon()方法吧线程设为守护线程,然后才能start()开启运行,否则会报出java.lang.IllegalThreadStateException异常,原因是不能对正在运行的线程做线程类型设置。
- 守护线程内创建的线程也是守护线程,也是随着用户线程死亡而死亡。
- 守护线程不能执行读写操作等业务代码,因为守护线程的退出不是以程序执行完毕来结束而是由jvm控制的,因此有可能完不成预期的任务。
//用户线程
class RunnableTest implements Runnable{
public void run() {
//输出1到3自然数,每隔1秒输出一次
for(int i=1; i<=3; i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("用户线程正在执行,i = " + i);
}
System.out.println("用户线程结束");
}
}
//守护线程
class DaemonTest implements Runnable{
public void run() {
//输出1到5自然数,每隔一秒输出一次
for(int i=1; i<=5; i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("守护线程正在执行,i = " + i);
}
System.out.println("守护线程结束");
}
}
public class ThreadMain {
public static void main(String[] args) {
Thread userThread = new Thread(new RunnableTest());
Thread daemonThread = new Thread(new DaemonTest());
daemonThread.setDaemon(true);//设为守护线程
daemonThread.start();
userThread.start();
}
}
运行结果如下:
我们可以看到用户线程和守护线程是在同步运行的,但是用户线程的代码全部执行完毕,而守护线程的代码却提前结束了,这就是说明当用户线程执行完毕,守护线程会提前结束运行,因此不可以使用守护线程去执行读写操作。