实现多线程的三种方法
创建线程有三种方式,分别是继承Thread类、实现Runnable接口、实现Callable接口。
通过继承Thread类来创建并启动线程的步骤如下:
-
定义Thread类的子类,并重写该类的run()方法,该run()方法将作为线程执行体。
-
创建Thread子类的实例,即创建了线程对象。
-
调用线程对象的start()方法来启动该线程。
代码实现:
public class MyThreadDemo{ public static void main(String[] args) { MyThread my1=new MyThread(); MyThread my2=new MyThread(); //void start()到时此线程开始执行,java虚拟机调用此线程的run()方法 my1.start(); my2.start(); } }
public class MyThread extends Thread{ //重写run方法 @Override public void run() { for(int i=0;i<500;i++){ System.out.println(i); } } }
通过实现Runnable接口来创建并启动线程的步骤如下:
-
定义Runnable接口的实现类,并实现该接口的run()方法,该run()方法将作为线程执行体。
-
创建Runnable实现类的实例,并将其作为Thread的target来创建Thread对象,Thread对象为线程对象。
-
调用线程对象的start()方法来启动该线程。
代码实现:
public class MyRunnableDemo { public static void main(String[] args) { // 1.定义一个类MyRunnable实现Runnable接口 // 2.在MyRunnable类中重写run()方法 // 3.创建MyRunnable类的对象 MyRunnable my=new MyRunnable(); // 4.创建Thread类的对象,把MyRunnable对象作为构造方法的参数 //Thread(Runnable target) // Thread t1=new Thread(my); // Thread t2=new Thread(my); //Thread(Runnable target,String name) Thread t1=new Thread(my,"高铁"); Thread t2=new Thread(my,"飞机"); // 5.启动线程 t1.start(); t2.start(); } }
public class MyRunnable implements Runnable{ @Override public void run() { for (int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } }
通过实现Callable接口来创建并启动线程的步骤如下:
-
创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法有返回值。然后再创建Callable实现类的实例。
-
使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
-
使用FutureTask对象作为Thread对象的target创建并启动新线程。
-
调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
public static void main(String[] args) throws InterruptedException, ExecutionException { MyCallable<String> mc=new MyCallable<String>(); FutureTask<String> ft=new FutureTask<String>(mc); new Thread(ft).start(); String result=ft.get(); System.out.println(result); }
public class MyCallable<String> implements Callable<String> { private int tickt=10; @Override public String call() throws Exception { // TODO Auto-generated method stub String result; while(tickt>0) { System.out.println("票还剩余:"+tickt); tickt--; } result=(String) "票已卖光"; return result; } }
扩展阅读
通过继承Thread类、实现Runnable接口、实现Callable接口都可以实现多线程,不过实现Runnable接口与实现Callable接口的方式基本相同,只是Callable接口里定义的方法有返回值,可以声明抛出异常而已。因此可以将实现Runnable接口和实现Callable接口归为一种方式。
采用实现Runnable、Callable接口的方式创建多线程的优缺点:
-
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
-
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
-
劣势是,编程稍稍复杂,如果需要访问当前线程,则必须使用Thread.currentThread()方法。
采用继承Thread类的方式创建多线程的优缺点:
-
劣势是,因为线程类已经继承了Thread类,所以不能再继承其他父类。
-
优势是,编写简单,如果需要访问当前线程,则无须使用Thread.currentThread()方法,直接使用this即可获得当前线程。
鉴于上面分析,因此一般推荐采用实现Runnable接口、Callable接口的方式来创建多线程。
继承VS接口
实现接口会更好一些,因为:
Java 不支持多重继承,因此继承了 Thread 类就无法继承其它类,但是可以实现多个接口; 类可能只要求可执行就行,继承整个 Thread 类开销过大。
三种方式的区别
实现 Runnable 接口可以避免 Java 单继承特性而带来的局限;增强程序的健壮性,代码能够被多个线程共享,代码与数据是独立的;适合多个相同程序代码的线程区处理同一资源的情况。
继承相对来说编写简单,可以直接操纵线程;继承 Thread 类和实现 Runnable 方法启动线程都是使用 start() 方法,然后 JVM (Java虚拟机)将此线程放到就绪队列中,如果有处理机可用,则执行 run() 方法。
实现 Callable 接口要实现 call() 方法,并且线程执行完毕后会有返回值。其他的两种都是重写 run() 方法,没有返回值。
call()方法可抛出异常,而run()方法是不能抛出异常的。
Runnable ⾃ Java 1.0 以来⼀直存在,但 Callable 仅在 Java 1.5 中引⼊,⽬的就是为了来处理 Runnable 不⽀持的⽤例。 Runnable 接⼝不会返回结果或抛出检查异常,但是 Callable 接⼝ 可以。所以,如果任务不需要返回结果或抛出异常推荐使⽤ Runnable 接⼝,这样代码看起来会 更加简洁。
转载至:
https://blog.csdn.net/weixin_42606135/article/details/81282736
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?