自定义类,继承Thread类,并重写run()方法.
class MyThread1 extends Thread { @Override public void run() { System.out.println("第一种方式Thread " + Thread.currentThread().getName()); } } public class Test { public static void main(String[] args) throws Exception { //第一种方式 MyThread1 thread1 = new MyThread1(); thread1.start(); MyThread1 thread1 = new MyThread1(); thread1.start(); MyThread1 thread2 = new MyThread1(); thread2.setName("zz"); thread2.start(); // 运行结果 // 第一种方式Thread Thread-0 // 第一种方式Thread Thread-1 // 第一种方式Thread zz // 若不指定Name属性,能默认计数器0,1,2,3,4,5 } }
自定义类,实现Runnable接口的run方法. since JDK1.0
class MyThread2 implements Runnable { @Override public void run() { System.out.println("第二种方式Runnable " + Thread.currentThread().getName()); } } public class Test { public static void main(String[] args) throws Exception { //第二种方式 Thread thread2 = new Thread(new MyThread2()); thread2.start(); // Lambda表达式方式->因为Runnable被注解FunctionalInterface标识表明该接口是一个函数式接口 new Thread(() -> { System.out.println("第二种方式Runnable_Lambda " + Thread.currentThread().getName()); }).start(); // 运行结果 // 第二种方式Runnable Thread-0 // 第二种方式Runnable_Lambda Thread-1 } }
已知Runnable的run方法无返回值,所以引入了有返回值的Callable接口
FutureTask中构造方法如下.
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable }
FutureTask类结构图如下.
因为FutureTask类实现了Runnable接口,所以线程实现方法如下.
public class Test { public static void main(String[] args) throws Exception { //第三种方式 FutureTask<String> thread3 = new FutureTask<>(new MyThread3()); new Thread(thread3).start(); System.out.println(thread3.get()); //获得回调值 FutureTask<String> thread4 = new FutureTask(()->{ System.out.println("Call"); return "Lambda回调"; }); new Thread(thread4).start(); System.out.println(thread4.get()); // 运行结果 // 第三种方式Callable Thread-0 // 回调 // Call // Lambda回调 } } class MyThread3 implements Callable<String> { @Override public String call() throws Exception { System.out.println("第三种方式Callable " + Thread.currentThread().getName()); return "回调"; } }
交付线程池两种方式 submit或者execute方法,前者可接受Callable接口对象,有返回值,后者无返回值
public class Test { public static void main(String[] args) throws Exception { //第一种方式 MyThread1 thread1 = new MyThread1(); thread1.start(); //第二种方式 Thread thread2 = new Thread(new MyThread2()); thread2.start(); //第三种方式 FutureTask<String> thread3 = new FutureTask<>(new MyThread3()); new Thread(thread3).start(); System.out.println(thread3.get()); //第四种方式 ExecutorService pool = Executors.newFixedThreadPool(5); Future<?> submit1 = pool.submit(new MyThread1()); Future<?> submit2 = pool.submit(new MyThread2()); Future<?> submit3 = pool.submit(new MyThread3()); System.out.println(submit1.get() + " " + submit2.get() + " " + submit3.get()); pool.shutdown(); // 运行结果 // 第一种方式Thread Thread-0 // 第二种方式Runnable Thread-1 // 第三种方式Callable Thread-2 // 回调 // 第一种方式Thread pool-1-thread-1 // 第二种方式Runnable pool-1-thread-2 // 第三种方式Callable pool-1-thread-3 // null null 回调 } }
无论何种方式,都要使用Thread类中start方法开始多线程.
Runnable接口和Callable接口区别,后者可返回参数,参数类型Object.
线程池避免了线程频繁使用的创建和释放操作.