在java中,创建线程有以下四种方式:
- 1.继承Thread类
- 2.实现Runnable接口
- 3.实现Callable接口(用到Future)
- 4.使用线程池(用到Executor)
以下是四种创建方式的具体步骤和实现代码。
方式1:继承Thread类
步骤:
(1)创建一个继承于Thread类的子类
(2)重写Thread类的run()方法,此线程执行的操作在run()中实现
(3)创建Thread类的子类的对象
(4)通过此对象调用start()启动线程,调用run()中的代码。
代码:
// 1.创建继承于Thread类的子类
public class FirstThread extends Thread{
// 2.重写run()方法,线程要执行的操作写在run()里面
public void run() {
System.out.println("使用继承Thread类的方式创建线程...");
}
public static void main(String[] args) {
// 3.创建Thread类的子类对象
FirstThread ft1 = new FirstThread();
FirstThread ft2 = new FirstThread(); //创建多个线程
// 4.通过此对象调用start() ①启动线程、②调用当前线程的run()
ft1.start();
ft2.start();
}
}
方式2:实现Runnable接口
步骤:
(1)创建一个实现Runnable接口的类
(2)实现类去实现Runnable接口的中的抽象方法run()
(3)创建实现类的对象
(4)将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
(5)通过Thread类的对象调用start()启动线程。
代码:
// 1.创建实现Runnable接口的子类
public class RunnableThread implements Runnable{
// 2.实现run()方法,线程要执行的操作写在run()里面
public void run() {
System.out.println("使用实现Runnable接口的方式创建线程...");
}
public static void main(String[] args) {
// 3.创建实现类的对象
RunnableThread rt = new RunnableThread();
// 4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread t1 = new Thread(rt);
Thread t2 = new Thread(rt); //创建多个线程
// 5.通过Thread类的对象调用start()
t1.start();
t2.start();
}
}
方法3:实现Callable接口(JDK5.0 新增)
步骤:
(1)创建一个实现Callable接口的实现类
(2)实现call()方法,将此线程要执行的操作声明在call()中
(3)创建Callable接口的实现类的对象
(4)将此Callable接口实现类的对象作为参数传递到FutureTask的构造器中,创建FutureTask的对象
(5)将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread类的对象
(6)通过Thread类的对象调用start()启动线程。
代码:
// 1.创建实现Callable接口的子类
public class CallableThread implements Callable {
// 2.实现call()方法,线程要执行的操作写在run()里面
public Object call() throws Exception {
String name = "我是call的返回值";
System.out.println("使用实现Callable接口的方式创建线程...");
return name;
}
public static void main(String[] args) {
// 3.创建实现Callable接口的实现类的对象
CallableThread ct = new CallableThread();
// 4.将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象
FutureTask ft = new FutureTask(ct);
// 5. 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象
Thread t1 = new Thread(ft);
// 6.通过Thread类的对象调用start()
t1.start();
try {
Object str = ft.get(); // 获取call()的返回值
System.out.println(str);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
方法4:使用线程池(JDK5.0 新增)
步骤:
(1)提供指定线程数量的线程池
(2)执行指定的线程操作,需要提供实现Runnable或者Callable接口实现类的对象
(3)关闭连接池
代码:
class Thread1 implements Callable{
@Override
public Object call() throws Exception {
System.out.println("使用线程池(Callable)方式创建线程...");
return null;
}
}
public class ThreadPool implements Runnable{
public void run() {
System.out.println("使用线程池(Runnable)方式创建线程...");
}
public static void main(String[] args) {
// 1. 提供指定线程数量的线程池
ExecutorService service = Executors.newFixedThreadPool(10);
// 2.执行指定的线程操作,需要提供实现Runnable或者Callable接口实现类的对象
// service.execute(new ThreadPool()); // execute使用Runnable的实现类对象
service.submit(new Thread1()); // submit 使用Callable的实现类对象
// 3.关闭连接池
service.shutdown();
}
}
四种创建方式的对比
- 实现Runnable与实现Callable接口的方式对比:
(1) call()方法是有返回值的;
(2) call()方法可以抛出异常,线程出现可以进行捕获;
(3) Callable是支持泛型的。 - 实现(Runnable,Callable)接口方式与继承Thread类的对比:
(1) 实现Runnable或者Callable接口,还可以继承其他类,而继承Thread类后无法继承其他类(Java中只支持单继承)。
(2) 实现方式所有线程共用一个Runnable的实现类对象创建线程,适用于多个线程有共享数据的情况。 - 使用线程池的方式提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁,实现重复利用。线程池的方法还便于对线程进行管理。