🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 实现线程的三种方式 ## 继承Thread ~~~ package testThread; import java.util.Random; public class MyThreadWithExtends extends Thread { private String flag; public MyThreadWithExtends(String flag) { this.flag = flag; } @Override public void run() { //获取当前线程的线程名 String tname = Thread.currentThread().getName(); System.out.println(tname + "线程的run方法被调用..."); Random random = new Random(); for (int i = 0; i < 20; i++) { try { Thread.sleep(random.nextInt(10) * 100); System.out.println(tname + "..." + flag); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { Thread thread1 = new MyThreadWithExtends("a"); Thread thread2 = new MyThreadWithExtends("b"); thread1.start(); thread2.start(); //如果调用run方法只是一个普通的方法调用,是不会开启新的线程的 } } ~~~ ## 声明实现 Runnable 接口的类 ~~~ package testThread; public class MyThreadWithImpliment implements Runnable { private final int x; public MyThreadWithImpliment(int x) { this.x = x; } @Override public void run() { String name = Thread.currentThread().getName(); System.out.println("线程---" + name + "---的run方法被调用"); for (int i = 0; i < 10; i++) { System.out.println(x); try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { Thread thread1 = new Thread(new MyThreadWithImpliment(1), "thread-1"); Thread thread2 = new Thread(new MyThreadWithImpliment(2), "thread-2"); thread1.start(); thread2.start(); //注意调用run和调用start的区别,直接调用run,则都运行在main线程中 } } ~~~ ## 还可以实现Callable接口 Callable接口类似于Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的,方法可以有返回值,并且可以抛出异常。但是Runnable不行。 Callable需要依赖FutureTask,用于接收运算结果。一个产生结果,一个拿到结果。FutureTask是Future接口的实现类,也可以用作闭锁。 ~~~ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /* * 一、创建执行线程的方式三:实现 Callable 接口。 相较于实现 Runnable 接口的方式,方法可以有返回值,并且可以抛出异常。 * * 二、执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。 FutureTask 是 Future 接口的实现类 */ public class TestCallable { public static void main(String[] args) { ThreadDemo td = new ThreadDemo(); //1.执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。 FutureTask<Integer> result = new FutureTask<>(td); new Thread(result).start(); //2.接收线程运算后的结果 try { Integer sum = result.get(); //FutureTask 可用于 闭锁 类似于CountDownLatch的作用,在所有的线程没有执行完成之后这里是不会执行的 System.out.println(sum); System.out.println("------------------------------------"); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } class ThreadDemo implements Callable<Integer> { @Override public Integer call() throws Exception { int sum = 0; for (int i = 0; i <= 100000; i++) { sum += i; } return sum; } } ~~~ get获取结果是阻塞的 综上例子可以看到: Callable 和 Future接口的区别 1. Callable规定的方法是call(),而Runnable规定的方法是run(). 2. Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。 3. call()方法可抛出异常,而run()方法是不能抛出异常的。 4. 运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。 它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。 通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。 Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。