如何创建并运行Java线程

创建并运行Java线程的两种方法。


方法1: 实现Runnable接口

先来看一下Runnable接口,非常简单,里面只有一个run()方法:

1
2
3
public interface Runnable {
public abstract void run();
}

实现了Runnble接口的类的对象是被用来创建线程的,start这个线程会导致对象的run方法在这个线程中被调用。

最常使用的方法是在Thread的构造方法中传入一个实现了Runnable接口的匿名内部类,如下所示:

1
2
3
4
5
6
7
8
public static void main(String[] args) {
Thread myThread = new Thread(new Runnable() {
public void run() {
System.out.println("myThread is running");
}
});
myThread.start();
}

当新建的线程很多的时候,为了区分线程,需要给线程起个名字,可以在Thread构造方法中直接传入新建线程的名字,然后使用Thread.currentThread().getName()来得到这个线程的名字。

1
2
3
4
5
6
7
8
public static void main(String[] args) {
Thread myThread = new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName());
}
}, "myThread");
myThread.start();
}

注意:在启动线程时要使用Thread.start(),不能直接调用Thread.run()。使用start()方法JVM会新建一个线程然后使用新建的线程执行run()方法,如果直接调用run()方法,JVM不会新建线程,相当于在当前线程中执行Thread对象中的run()方法。

方法2: 创建Thread的子类

Thread类实现了Runnable接口,我们可以创建Thread类的子类,然后重写run()方法,然后通过新建该类的对象来新建线程。

1
2
3
4
5
6
7
8
9
10
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("this is MyThread");
}
}
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
}

也可以创建一个Thread的匿名子类对象来新建线程。

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("this is myThread");
}
};
thread.start();
}

方法3: 实现Callable接口

java.util.concurrent.Callable接口里面只有一个方法,跟Runnable接口很类似,Callable接口源码如下:

1
2
3
public interface Callable<V> {
V call() throws Exception;
}

使用这种方法创建线程分以下几步:

1.创建一个类实现Callable接口中的call()方法.

1
2
3
4
5
6
7
public static class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + " is running");
return 1;
}
}

2.新建Callable对象,使用Callabe对象作为传入参数新建FutureTask对象,FutureTask对Callable的call()方法的返回值进行了封装,然后使用FutureTask对象作为参数新建Thread对象,然后使用Thread.start()方法启动线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadExample02 {
public static class MyThread implements Callable<Integer> {

@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName() + " is running");
return 1;
}
}

public static void main(String[] args) {
Callable myThread = new MyThread();
FutureTask<Integer> futureTask = new FutureTask<Integer>(myThread);
Thread thread = new Thread(futureTask, "myThread");
thread.start();
try {
System.out.println("子线程返回值 :" + futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}

三种方法对比

使用时间Runnable,Callable接口的方法:

  • 优势:由于只实现了接口,所以还可以继承其他类。多个Thread可以共享同一个target对象,适合多个相同线程来处理同一份资源的情况,可以将CPU、代码和数据分开,形成清晰的模型。
  • 劣势:编程复杂,访问当前线程必须使用Thread.currentThread()方法。

使用继承Thread类的方法:

  • 优势:编程简单,访问当前线程直接使用this。
  • 劣势:由于线程类已经继承了Thread类,所以不能再继承其他类。