Java创建线程的三种方式
一、直接使用Thread创建(继承Thread类)
这种方式通过直接覆盖Thread
类中的run
方法创建线程
- 继承Thread类
- 首先创建一个类,
继承
自Thread类 - 然后
重写
Thread的run方法,方法里面写要并发执行的代码 - 在main方法里面创建线程,使用
start
方法开启线程。(注意:一定要使用start
而不是run方法开启线程。如果直接调用run()方法,程序将执行完run()方法后才会执行main()方法中后面的代码,这样就是单线程执行而不是多线程并发执行了)
//继承Thread类
class MyThread extends Thread{
//重写run方法
public void run() {
//t1线程
System.out.println(Thread.currentThread().getName() + " is running");
}
}
public class Test1 {
public static void main(String[] args) {
Thread t = new MyThread();
//设置线程名字
t.setName("t1");
//开启线程
t.start();
//主线程
System.out.println(Thread.currentThread().getName() + " is running");
}
}
打印结果:
可以看到是先执行了main线程里面的 sout语句,然后才执行 t1线程的语句。说明是并发执行的。
-
直接重写Thread方法
这种方式与上面创建的方式一样,不过会简洁一点。
public static void main(String[] args) { Thread t = new Thread(){ //重写run方法 public void run() { System.out.println(Thread.currentThread().getName() + " is running"); } }; t.setName("t1"); t.start(); System.out.println(Thread.currentThread().getName() + " is running"); }
二、 使用Runnable配合Thread
优点:
把线程
和任务
(要执行的代码)分开,通过组合而不是继承的方式创建了线程。这让代码更加的灵活,
Thread 代表线程
Runnable 代表任务
public static void main(String[] args) {
//创建一个任务
Runnable runnable = new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + " is running");
}
};
//使用Thread类,将runable作为参数创建线程
Thread t = new Thread(runnable , "t2");
//开启线程
t.start();
System.out.println(Thread.currentThread().getName() + " is running");
}
结果:
-
小结
-
方法1 是把线程和任务合并在了一起,方法2 是把线程和任务分开了
-
用 Runnable 更容易与线程池等高级 API 配合
-
用 Runnable 让任务类脱离了 Thread 继承体系,更灵活。使用了组合的方式创建线程。
-
三、配合Callable接口和Future创建线程
这种方式可以获得线程的返回值,FutureTask 能够接收 Callable 类型的参数,用来处理有返回结果的情况
在使用这个方式创建线程之前,首先要明白FutureTask的继承关系。可以看到FutureTask实现了RunnableFuture接口。而此接口又继承了Runnable和Future接口。所以FutureTask实际上也是一个Runnable,它除了实现Runnable接口以外,还实现了Future接口。而获得线程的返回值正是通过这个接口进行实现的。
-
首先要创建实现了Callable接口的实现类MyCallable,实现call方法。Callable接口是一个泛型接口,其类型就是返回值的类型。实现Callable接口中的call()方法,方法的返回类型与泛型的类型相同。
class MyCallable implements Callable<Integer>{ //重写call 方法 public Integer call() throws Exception { System.out.println(Thread.currentThread().getName() + " is running"); //睡眠1s Thread.sleep(1000); //返回100 return 100; } }
-
Callable不能直接获取返回值,需要用FutureTask在外部封装一下再获取返回值
在使用task.get() 方法获取返回值时,是阻塞式的等待。上面callable接口在返回值之前睡眠了1s,则这个get方法就会阻塞式的等待1s
public static void main(String[] args) throws ExecutionException, InterruptedException { //创建Callable接口实现类 Callable callable = new MyCallable(); //创建FutrueTask类 FutureTask<Integer> task = new FutureTask<>(callable); //创建线程,task实现了Runnable接口 Thread t = new Thread(task,"t1"); t.start(); //调用get方法获取返回值 System.out.println(Thread.currentThread().getName() + " " + task.get()); }
-
结果
执行完线程t1,然后通过get方法获得了返回值