Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。
启动线程的唯一方法就是通过 Thread 类的 start() 实例方法。start() 方法是一个 native 方法,它将启动一个新线程,并执行 run() 方法。
public class ThreadTest extends Thread {
@Override
public void run() {
System.out.println("继承Thread,重写run方法");
}
// 测试调用
public static void main(String[] args) throws InterruptedException {
ThreadTest threadTest = new ThreadTest();
threadTest.start();
Thread.sleep(3000);
}
}
public class ThreadRunnable implements Runnable { // 新建实现 Runnable 接口的类
@Override
public void run() {
System.out.println("实现Runnable方法");
}
// 测试调用
public static void main(String[] args) throws InterruptedException {
ThreadRunnable threadTest2 = new ThreadRunnable();
// 由 Runnable 的实例创建一个Thread对象
Thread thread = new Thread(threadTest2);
// 启动线程
thread.start(); // 启动 ThreadTest2 这个线程实例
thread.run();// 只是执行run这个方法
}
}
新建实现 Runnable 接口的类ThreadRunnable —> 创建 该实现类的对象实例 —> 由Runnable的实现类对象创建一个Thread对象 —> 启动线程
至此,一个线程就创建完成了。
线程的执行流程很简单,当执行代码oneThread.start();时,就会执行oneRunnable对象中的void run();方法,
该方法执行完成后,线程就消亡了。
public class ThreadTestCallable implements Callable<String> { // 新建实现 Callable 接口的类
@Override
public String call() throws Exception {
System.out.println("实现callable接口");
return "重写call方法返回一个对象";
}
public static void main(String[] args) throws Exception {
// 创建一个类对象
ThreadTestCallable threadTestCallable = new ThreadTestCallable();
// Callable 比 runnable多了一步:创建了 callable实例后需要创建一个对应的 FutureTask 对象,再由这个对象FutureTask创建Thread
FutureTask<String> stringFutureTask = new FutureTask<>(threadTestCallable);
Thread thread = new Thread(stringFutureTask);
thread.start(); // 启动 ThreadTest2 这个线程实例
}
}
创建实现Callable接口的类ThreadTestCallable —> 创建ThreadTestCallable该实现类的对象实例 —> 由 ThreadTestCallable 实例创建一个FutureTask对象 —> 由FutureTask的实例创建一个Thread对象 —> 启动线程
注意:FutureTask
是一个包装器,它通过接受Callable 来创建,它同时实现了Future和Runnable接口。
至此,一个线程就创建完成了。
三种方式相同点: 都采用Thread.start()启动线程
不同点:
继承 Thead 类实现多线程,可以直接通过实例对象调 start() 启动线程来执行。但实现 Callable和Runnable无法直接调用 start()。
Callable规定的方法是call(),Runnable规定的方法是run()。
Callable的任务执行后有返回值,而Runnable的任务是没有返回值的。
call() 方法可以抛出异常,run() 方法不可以。
运行Callable任务可以拿到一个Future对象,c表示异步计算的结果。
注:Callalbe接口支持返回执行结果,需要调用 FutureTask.get() 得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。
参考文章:https://blog.csdn.net/weixin_44814196/article/details/140997805
步骤1:创建线程池:
ExecutorService executor = Executors.newCachedThreadPool();
步骤2:通过将 Runnable对象或Callable对象将要执行的任务提交给线程池的ExecutorService对象
executor.submit(threadTestCallable实例对象);
步骤3:关闭线程池,等待所有任务完成
// 关闭线程池,等待所有任务完成
executor.shutdown();
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
// 创建线程池
ExecutorService executor = Executors.newCachedThreadPool();
// ThreadTestCallable实例对象
ThreadTestCallable threadTestCallable = new ThreadTestCallable();
// 提交实例对象,执行实例中的任务
executor.submit(threadTestCallable);
executor.shutdown();
}
}
注意:shutdown
方法并不会立即停止正在运行的任务,而是不允许提交新的任务。