首先我们来看一下线程的生命周期,线程生命周期分为创建、就绪、运行、阻塞、终止、死亡:
我们通过图来说明一下:
①首先是建立线程,然后创建任务,就可以使用start启动了
②启动之后,就会进入到就绪状态,等待CPU的调度
③当CPU有资源的时候,那些就绪的线程就会开始争抢资源,争抢到资源就进入运行状态;每个线程是有时间片的,如果时间片到了,或者进行了yield操作,就会从运行状态又返回到就绪状态。而运行状态是在线程的run方法中进行的
④如果运行的时候被暂停,那么就会进入阻塞状态,通常是通过sleep、wait进行暂停,sleep是休眠,线程不释放锁,wait是等待,会释放锁,只有当阻塞解除的时候,它们才会再次进入就绪状态
⑤如果运行完毕,即run方法结束,就会死亡,即此线程销毁。
要实现线程,Java提供了Thread和Runnable,其中Thread是一个类,而Runnable是一个接口,其实通过查看API我们可以发现,Thread其实是Runnable的一个实现类。
Thread是由子类来继承它,并重写run()方法来实现的;Runnable是由一个类来实现它,然后重写run()方法;启动的话,是使用start方法来启动,而不是通过run方法。为什么是start而不是run呢?其实从上面的生命周期图就可以看出来。start其实就是让其启动,进入到就绪状态;run方法才是让其由就绪状态进入到运行状态。
下面我们分别使用Thread和Runnable来创建线程并启动它。
使用Thread创建线程并启动:
public class MyThread extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("开启线程!");
}
}
//测试启动线程,继承Thread
@Test
public void t1(){
MyThread mt = new MyThread();
mt.start();
}
使用Runnable创建线程并启动,Runnable有两种方式来启动线程,一种是通过匿名内部类的方式,另外一种是通过Thread的构造方法new Thread(Runnable target):
①通过Thread的构造方法new Thread(Runnable target)启动:
public class Task implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("线程被启动啦!");
}
}
@Test
public void t2() {
// TODO Auto-generated method stub
//通过Thread的构造方法
Task task = new Task();
Thread t = new Thread(task);
t.start();
}
②通过匿名内部类方式启动:
@Test
public void t2() {
//通过匿名内部类的方式来启动
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("启动!");
}
}).start();;
}