今天来讲讲Java如何创建一个线程。
大多数情况下,通过实例化一个Thread对象来创建一个线程,Java定义了两种方式:
实现Runnable接口
继承Thread类
实现Runnable接口
创建线程的最简单的方法就是创建一个Runnable口的类。Runnable抽象了一个执行代码单元。为实现Runnable接口,一个类仅需实现一个run()的简单方法,在run()方法中可以定义代码来构建新的线程。创建一个线程必须理解下面这段话:
run()方法能够让主线程那样调用其他方法,引用其他类,声明变量。仅有的不同的是run()方法在程序中确立另一个并发的线程执行入口。当run()方法运行完毕时,该线程结束。
在你已经创建了实现Runnable接口的类以后,你要在类内部实例化一个Thread类的对象。
Thread(Runnable threadOb,String threadName)
该构造函数中,threadOb时一个实现Runnable接口的实现类,threadName参数则是你新建线程的线程名称,这定义了线程执行的起点。
建立了新的线程,它并不能运行,需要调用start方法来执行线程的run()方法。本质上,start()方法执行的是一个对run()的调用。
public class Test1 {
public static void main(String[] args) throws InterruptedException {
new XkThread();
try {
for(int i=1;i<=5;i++){
Thread.currentThread().sleep(1000);//让当前线程睡眠1秒
System.out.println("大家好,我是主线程:"+i);
}
//需要捕获sleep()方法可能抛出的异常
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class XkThread implements Runnable {
private Thread th;
public XkThread() {
th=new Thread(this);
System.out.println("开始调用run()方法");
th.start();//调用run()方法
}
@Override
public void run() {
try {
for(int i=1;i<=5;i++){
th.sleep(1000);//让线程睡眠1秒
System.out.println("大家好,我是子线程:"+i);
}
//需要捕获sleep()方法可能抛出的异常
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在NewThread中构造函数中,新的Thread对象由下面语句创建:
th=new Thread(this);
通过前面的语句this表明了在this对象中你想要新的线程调用run()方法。然后start()被调用,以run()方法为开始启动了线程的执行。这使子线程for循环开始执行。调用start()方法之后,NewThread的构造函数返回到main()。当主线程被恢复,主线程开始执行自己的for循环。两个线程同时运行,共享CPU,直到它们的循环结束。
运行结果:
开始调用run()方法
大家好,我是主线程:1
大家好,我是子线程:1
大家好,我是子线程:2
大家好,我是主线程:2
大家好,我是子线程:3
大家好,我是主线程:3
//省略
继承Thread类
创建线程的另一个途径就是继承Thread类,然后创建子类的实例。当一个类继承Thread类时,它必须重写run()方法,这个run()方法时新线程的入口。它也必须调用start()方法来启用新线程执行。
public class Test2 {
public static void main(String[] args) {
new MyThread("child Thread");
System.out.println("开始执行主线程的for循环");
try {
for(int i=1;i<=5;i++){
Thread.currentThread().sleep(1000);//让主线程睡眠1秒
System.out.println("大家好,我是主线程:"+i);
}
//需要捕获sleep()方法可能抛出的异常
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThread extends Thread{
public MyThread(String threadName) {
super(threadName);
System.out.println("开始调用start()方法");
start();
}
@Override
public void run() {
System.out.println("开始执行子线程的for循环");
try {
for(int i=1;i<=5;i++){
sleep(500);//让子线程睡眠0.5秒
System.out.println("大家好,我是子线程:"+i);
}
//需要捕获sleep()方法可能抛出的异常
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
创建一个子线程MtThread,在构造函数中调用start()方法启动子线程,然后主线程也继续运行,为了让主线程最后结束,在这里我让子线程睡眠时间为0.5秒,主线程睡眠时间为1秒,这样子总可以让主线程最后结束。
运行结果:
开始调用start()方法
开始执行主线程的for循环
开始执行子线程的for循环
大家好,我是子线程:1
大家好,我是子线程:2
大家好,我是主线程:1
大家好,我是子线程:3
大家好,我是主线程:2
大家好,我是子线程:4
大家好,我是子线程:5
大家好,我是主线程:3
大家好,我是主线程:4
大家好,我是主线程:5
最后
到这里,你一定很奇怪为什么Java有两种创建子线程的方法呢?哪一种更好呢?所有的问题都归于一点,Thread类定义了多种方法可以被子类重载。对于所有的方法,唯一的必须重写的是run()方法。而实现Runnable接口也只需要重写run()方法。因此,如果你不重载Thread的其他方法,最好是实现Runnable接口。当然了,这得看个人习惯。