Java 代码创建线程,实现多线程的四种方式
目录1. 继承 Thread 类实现多线程2. 实现 Runnable 接口的方式实现多线程3. 利用 Callable 和 Future 接口实现多线程4. 线程池创建对象实现多线程5. 总结概括1. 继承 Thread 类实现多线程想要实现多线程第一种方法就是通过继承 Thread 类实现多线程Thread 类是 Java 中定义的的一个线程类里面有很多关于线程的方法直接继承 Thread 类创建对象就可以创建线程并实现多线程在讲解之前需要先简单罗列几个 Thread 类中的几个成员方法这里先主要记住画红线的三个方法其它的在本篇中暂时用不到继承 Thread 类实现多线程有以下几步1我们要先自定义一个类然后继承Thread类2在继承 Trread 的类中重写 run 方法3通过创建该类的对象即可创建线程创建多个对象就可以实现多线程4这种实现多线程的方式无法获取多线程的结果如下代码我先定义了一个 ThreadTest01 类// 创建一个类继承 Thread 类 public class Thread01 extends Thread{ // 重写 run 方法 Override public void run(){ for (int i 0; i 5; i) { // 通过getName() 获取线程名称 System.out.println(getName()多线程); } } }我们在另一个类中写一个 main 方法创建 ThreadTest01类的对象然后就可以实现多线程代码如下public class TestThread01 { public static void main(String[] args) { // 创建线程 t1 Thread01 t1 new Thread01(); // 创建线程 t2 Thread01 t2 new Thread01(); // 给 t1 线程添加一个名字做区分 t1.setName(线程1); // 给 t2 线程添加一个名字做区分 t2.setName(线程2); // 通过 start 启动线程 t1.start(); t2.start(); } }运行上述 main 方法即可在在控制台中得到如下结果我们可以看到创建的线程1与线程2交替执行最终都进行完成这就做到了多线程的效果。2. 实现 Runnable 接口的方式实现多线程通过实现 Runnable 接口的方式实现多线程也大致可以分为以下几步1自定义一个了类实现 Runnable 接口2重写 run 方法3创建自定义类的对象4创建 Thread 类对象将自定义对象作为参数传递给 Thread 对象5通过调用 start 方法启动线程实现多线程6这种实现多线程的方式也无法获取多线程的结果。代码如下所示首先先定义一个自定义类实现 Runnable 接口重写run方法。// 创建一个类实现 Runnable 接口 public class Thread02 implements Runnable{ // 重写 run 方法 Override public void run(){ for (int i 0; i 5; i) { /** * 这里有一个点需要注意刚才我们通过继承 Thread 实现多线程 * 之所以可以通过 getName()方法获取线程名称是因为getName()方法时 Thread 类中的 * 子类可以直接使用父类中的方法。 * 但现在我们是实现 Runnable 接口实现多线程就不能也无法直接调用 getName() 方法获取线程名称 * 但我们可以再创建一个 Thread 类的对象接收当前线程对象 * 然后再使用 getName() 方法获取当前线程对象名称 * 这一点需要注意哦 */ // 创建对象 t 获取当前线程对象 Thread t Thread.currentThread(); // 获取当前线程名称 System.out.println(t.getName() 多线程);//getName() } } }然后去另一个测试类写 main 方法测试多线程代码如下public class TestThread02 { public static void main(String[] args) { // 创建线程 Thread02的对象 Thread02 t1 new Thread02(); // new 一个线程将 t1 作为参数传递进去 Thread thread01 new Thread(t1); // 创建线程 thread02 的对象 Thread02 t2 new Thread02(); // 再 new 一个线程将 t2 作为参数传递进去 Thread thread02 new Thread(t2); // 给 t1 线程添加一个名字做区分 thread01.setName(线程1); // 给 t2 线程添加一个名字做区分 thread02.setName(线程2); // 通过 start 启动线程 thread01.start(); thread02.start(); } }运行 main 方法即可在控制台得到如下结果因为我循环次数较少可能效果不明显各位小伙伴自行测试的时候可以把 for 循环次数增多会更加直观一些3. 利用 Callable 和 Future 接口实现多线程其实这第三种方式是对前两种实现多线程方式的补充我们可以发现前两种方法实现多线程时重写 run 方法返回值都是 viod 因此无法获取多线程的执行结果而这第三种方法就可以。大致分为以下几步1创建一个自定义类实现 Callable 接口2重写 call (有返回值的表示多线程的运行结果);3创建自定义类的对象执行要执行的任务4创建 Future 的对象它可以管理多线程运行的结果但是 Future 是一个接口所以我们需要创建它的是实现类 FutureTask 的对象。5创建 Thread 的对象并调用 start 启动线程。先创建一个类实现 Callable 接口如下代码所示// 创建一个类实现 Callable 接口,这里要注意Callable需要传递一个泛型表示运行的结果类型 public class Thread03 implements CallableInteger { Override public Integer call() throws Exception { // 随便写一段逻辑求 1~100 的 整数和 int sum 0; for (int i 1; i 100; i) { sum sum i; } // 将计算的结果返回 return sum; } }我们去另一个类编写 main 方法测试这种带有返回值的线程的方法代码如下所示这里我只创建了一个线程实现多线程将代码复制一份改个名字运行即可public class TestThread03 { public static void main(String[] args) { // 创建线程 Thread03的对象 Thread03 t1 new Thread03(); // 将创建的 t1 对象作为参数传递给 FutureTask FutureTaskInteger futureTask new FutureTask(t1); // 创建 Thread 对象并把 futureTask 作为参数的传递进去 Thread thread new Thread(futureTask); // 通过 start 启动线程 thread.start(); // 获取线程的结果有异常使用 try。。。catch。。。 try { Integer num futureTask.get(); System.out.println(num); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }运行 main 方法即可在控制台得到1~100 的结果如下所示4. 线程池创建对象实现多线程ExecutorService pool Executors.newFixedThreadPool(2); // execute - 无返回值 pool.execute(() - { System.out.println(控制台打印execute 无返回值); }); // submit - 有返回值 FutureString future pool.submit(() - { Thread.sleep(1000); return return返回: submit执行结果; }); // 获取返回值会阻塞直到任务完成输出: submit: 执行结果 String result future.get(); System.out.println(result);execute 和 submit 两个方法都可以运行线程二者对比如下区别点execute()submit()返回值void无返回值FutureT可获取返回值任务类型只能执行Runnable可执行Runnable和Callable异常处理异常直接抛出到控制台异常被封装在Future.get()中使用场景不需要返回结果的任务需要返回结果或捕获异常的任务5. 总结概括1创建线程并实现多线程有四种方式。一是继承 Thread 类二是实现 Runnable 接口三是实现 Callable接口并利用 FutureTask 类接收线程结果四是通过创建线程池创建线程并实现多线程。2继承 Thread 类实现多线程不可以获取线程的结果实现 Runnable 接口实现多线程的方式也无法获取返回值结果。3继承只能单继承而接口却可以多实现。因此不难看出第一种继承 Thread 类实现多线程的方式是不太友好的虽然编程时较为简单但是可扩展性较差一旦我们的业务类还需要继承别的类就不行了所以不太推荐。而第二种与第三种方式均是通过实现接口的方式来实现多线程的也可以继承其他类实现其他接口虽然编写过程较复杂但可扩展性强但是也无法直接使用 Thread 类中的方法实际开发中最推荐的方法还是创建线程池线程池与手动创建线程优势明显如下表格对比维度手动创建线程线程池资源消耗每个任务都创建新线程开销大复用线程减少创建销毁开销响应速度需要等待线程创建线程已存在立即执行系统稳定性无限制创建可能导致OOM控制并发数系统稳定线程管理手动管理生命周期自动管理创建、销毁、回收任务队列无队列任务直接执行有队列缓冲削峰填谷