企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] ## 1. 继承Thread类 通过继承Thread类来创建并启动多线程的步骤如下: **1. 定义一个类继承Thread类,并重写Thread类的run()方法,run()方法的方法体就是线程要完成的任务,因此把run()称为线程的执行体;** **2. 创建该类的实例对象,即创建了线程对象;** **3. 调用线程对象的start()方法来启动线程;** ~~~ package com.tuna.javatest.thread; public class ExtendThread extends Thread { private int i; public void run() { for (; i < 10; i++) { //当通过继承Thread类的方式实现多线程时,可以直接使用this获取当前执行的线程 System.out.println(this.getName() + " " + i); } } public static void main(String[] args) { for (int j = 0; j < 5; j++) { //调用Thread类的currentThread()方法获取当前线程 System.out.println(Thread.currentThread().getName() + " " + j); //创建并启动第一个线程 new ExtendThread().start(); } } } ~~~ ## 2. 实现Runnable接口 这种方式创建并启动多线程的步骤如下: **1. 定义一个类实现Runnable接口;** **2. 创建该类的实例对象obj;** **3. 将obj作为构造器参数传入Thread类实例对象,这个对象才是真正的线程对象;** **4. 调用线程对象的start()方法启动该线程;** 推荐这种写法,体现设计与实现分离的思想 ~~~ package com.tuna.javatest.thread; public class ImpRunnable implements Runnable { private int i; @Override public void run() { for(;i < 5;i++) { //当线程类实现Runnable接口时,要获取当前线程对象只有通过Thread.currentThread()获取 System.out.println(Thread.currentThread().getName() + " " + i); } } public static void main(String[] args) { for(int j = 0;j < 30;j++) { System.out.println(Thread.currentThread().getName() + " " + j); ImpRunnable thread_target = new ImpRunnable(); new Thread(thread_target,j+"").start(); } } } ~~~ ## 3. Callable和Future接口创建线程 ### 3.1 Callable接口 通过实现Runnable接口创建多线程时,Thread类的作用就是把run()方法包装成线程的执行体,那么,是否可以直接把任意方法都包装成线程的执行体呢?从JAVA5开始,JAVA提供提供了Callable接口,该接口是Runnable接口的增强版,Callable接口提供了一个call()方法可以作为线程执行体,但call()方法比run()方法功能更强大,call()方法的功能的强大体现在: 1. call()方法可以有返回值; 2. call()方法可以声明抛出异常; 从这里可以看出,完全可以提供一个Callable对象作为Thread的target,而该线程的线程执行体就是call()方法。但问题是:Callable接口是JAVA新增的接口,而且它不是Runnable接口的子接口,所以Callable对象不能直接作为Thread的target。还有一个原因就是:call()方法有返回值,call()方法不是直接调用,而是作为线程执行体被调用的,所以这里涉及获取call()方法返回值的问题。 于是,JAVA5提供了Future接口来代表Callable接口里call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该类实现了Future接口,并实现了Runnable接口,所以FutureTask可以作为Thread类的target,同时也解决了Callable对象不能作为Thread类的target这一问题。 ### 3.2 Future接口 是对于具体的Runnable或者Callable任务的执行结果进行**取消**、**查询是否完成**、**获取结果** 。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。 接口中有5中方法: 1. **cancel(boolean mayInterruptIfRunning)** 方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。 参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。 2. **isCancelled()** 方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。 3. **isDone()** 方法表示任务是否已经完成,若任务完成,则返回true; 4. **get()** 方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回; 5. **get(long timeout, TimeUnit unit)** 用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。可用在任务超时控制的情形。 ### 3.3 线程实现 1. 实现Callable接口并重写call方法,完成要执行的逻辑 ~~~ class Task implements Callable<Object> { private String args1; private String args2; //构造函数,用来向task中传递任务的参数 public Task(String args1,String args2) { this.args1=args1; this.args2=args2; } //任务执行的动作 @Override public Object call() throws Exception { for(int i=0;i<10;i++){ System.out.println("call执行任务!"); } return true; } } ~~~ 2. 创建FutureTask对象(传入),将逻辑交给线程 ``` public static void main(String[] args) { Task myTask = new Task("11", "22");//实例化任务,传递参数 FutureTask<Object> futureTask = new FutureTask(myTask);//将任务放进FutureTask里 //采用thread来开启多线程,futuretask继承了Runnable,可以放在线程池中来启动执行 Thread thread = new Thread(futureTask); thread.start(); try { //get():获取任务执行结果,如果任务还没完成则会阻塞等待直到任务执行完成。如果任务被取消则会抛出CancellationException异常, //如果任务执行过程发生异常则会抛出ExecutionException异常,如果阻塞等待过程中被中断则会抛出InterruptedException异常。 boolean result = (boolean) futureTask.get(); System.out.println("result:" + result ); } catch (Exception e) { e.printStackTrace(); } } ``` 3. 完整代码 ~~~ class Task implements Callable<Object> { private String args1; private String args2; //构造函数,用来向task中传递任务的参数 public Task(String args1,String args2) { this.args1=args1; this.args2=args2; } //任务执行的动作 @Override public Object call() throws Exception { for(int i=0;i<10;i++){ System.out.println("call执行任务!"); } return true; } public static void main(String[] args) { Task myTask = new Task("11", "22");//实例化任务,传递参数 FutureTask<Object> futureTask = new FutureTask(myTask);//将任务放进FutureTask里 //采用thread来开启多线程,futuretask继承了Runnable,可以放在线程池中来启动执行 Thread thread = new Thread(futureTask); thread.start(); try { //get():获取任务执行结果,如果任务还没完成则会阻塞等待直到任务执行完成。如果任务被取消则会抛出CancellationException异常, //如果任务执行过程发生异常则会抛出ExecutionException异常,如果阻塞等待过程中被中断则会抛出InterruptedException异常。 boolean result = (boolean) futureTask.get(); System.out.println("result:" + result ); } catch (Exception e) { e.printStackTrace(); } } } ~~~ ``` call执行任务! call执行任务! call执行任务! call执行任务! call执行任务! call执行任务! call执行任务! call执行任务! call执行任务! call执行任务! result:true ```