创建线程的三种方式
1. 继承Thread类
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("这是一个新的线程");
}
}
public class ThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
2. 实现Runnable接口
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("这是一个新线程");
}
}
public class ThreadTest {
public static void main(String[] args) {
Thread myThread = new Thread(new MyRunnable());
myThread.start();
}
}
由于Java中只能实现单继承,如果采用方式一,则线程类就无法继承其他类了,所以实现Runnable接口创建线程的方式更受欢迎。
3. 实现Callable接口
在前面两种线程创建方式中,线程执行完毕后并没有返回值,而实现Callable接口创建线程可以在线程结束后返回一个值。
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName() + "is running");
Thread.sleep(2000);
return "线程执行完毕";
}
}
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable myCallable = new MyCallable();
FutureTask<String> futureTask=new FutureTask<>(myCallable);
Thread thread = new Thread(futureTask);
thread.start();
String result = futureTask.get();//此时主线程阻塞,等待thread线程执行完毕,获取返回值
System.out.println(result);
}
}
在上面的测试中,我们用到了FutureTask类,该类是Future接口的基本实现。它提供了可取消的异步计算,提供方法来检查计算是否完成,等待其完成,并检索计算结果。 结果只能在计算完成后使用方法get进行检索,如有必要,阻塞,直到准备就绪。 取消由cancel方法执行。 提供其他方法来确定任务是否正常完成或被取消。 计算完成后,不能取消计算。
需要注意的是,cancel方法取消任务的执行,也只是对目标线程发去中断请求而已:
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();//对线程发送中断信号,但目标线程是否中断,则取决于目标线程对中断信号的处理。
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}