【Java多线程】多线程实现的四种方式


多线程实现的方式有很多,本文只针对常见的四种方式。

一、继承Thread类,重写run方法

该方式无返回值,方式如下:

public class MyThread extends Thread{
    private String param;
    public MyThread(String param){
        this.param = param;
    }
    @Override
    public void run(){
        System.out.println("Current Thread Param:" + param
                +",Current Thread Name:"+Thread.currentThread().getName());
    }
    public static void main(String[] args){
        MyThread myThread = new MyThread("My Thread");
        myThread.start();
        System.out.println("Current Thread Name:"+Thread.currentThread().getName());
    }
}

输出结果:

Current Thread Param:My Thread,Current Thread Name:Thread-0
Current Thread Name:main

二、实现Runnable接口,重写run方法

该方式无返回值,方式如下:

public class MyRunnable implements Runnable{
    private String param;
    public MyRunnable(String param){
        this.param = param;
    }
    @Override
    public void run() {
        System.out.println("Current Thread Param:" + param
                +",Current Thread Name:"+Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable("My Runnable");
        Thread thread = new Thread(myRunnable);
        thread.start();
        System.out.println("Current Thread Name:"+Thread.currentThread().getName());
    }
}

输出结果:

Current Thread Param:My Runnable,Current Thread Name:Thread-0
Current Thread Name:main

三、通过Callable和FutureTask创建线程

Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务,只是 Callable 的 call() 方法允许线程有返回值,并且可抛出异常,而Runnable 的 run()方法是不能抛出异常的。

该方式有返回值,可以获取线程返回值,方式如下:

public class MyCallable implements Callable<String> {
    private String param;

    public MyCallable(String param){
        this.param = param;
    }

    @Override
    public String call() throws Exception {
        System.out.println("Current Thread Param:" + param
                +",Current Thread Name:"+Thread.currentThread().getName());
        Thread.sleep(2000);
        return param + " is executed";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable myCallable = new MyCallable("My Callable");
        FutureTask<String> futureTask = new FutureTask(myCallable);
        Thread thread = new Thread(futureTask);
        thread.start();
        System.out.println("Current Thread Name:"+Thread.currentThread().getName());
        if (!futureTask.isDone()){
            System.out.println("thread task is not finished, plase wait");
        }
        System.out.println("Thread Return:"+futureTask.get());

    }
}

输出结果:

Current Thread Param:My Callable,Current Thread Name:Thread-0
Current Thread Name:main
thread task is not finished, plase wait
Thread Return:My Callable is executed

总结:
首先,FutureTask类的实现继承关系,结构图如下:
FutureTask继承关系图

  1. FutureTask 实现了 RunnableFuture 接口
  2. RunnableFuture 接口多继承了 Runnable 和 Future 接口类
  3. Runnable 接口只有一个 run 方法
    @FunctionalInterface
    public interface Runnable {
    public abstract void run();
    }
    
  4. Future 就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作,接口中有以下几个方法:
    public interface Future<V> {
    	//用来取消异步任务的执行。如果异步任务已经完成或者已经被取消,或者由于某些原因不能取消,则会返回false。
    	//如果任务还没有被执行,则会返回true并且异步任务不会被执行。
    	boolean cancel(boolean mayInterruptIfRunning);
    	//判断任务是否被取消,如果任务在结束(正常执行结束或者执行异常结束)前被取消则返回true,否则返回false。
    	boolean isCancelled();
    	//判断任务是否已经完成,如果完成则返回true,否则返回false。
    	//需要注意的是:任务执行过程中发生异常、任务被取消也属于任务已完成,也会返回true。
    	boolean isDone();
    	//获取任务执行结果,如果任务还没完成则会阻塞等待直到任务执行完成。如果任务被取消则会抛出CancellationException异常,
    	//如果任务执行过程发生异常则会抛出ExecutionException异常,如果阻塞等待过程中被中断则会抛出InterruptedException异常。
    	V get() throws InterruptedException, ExecutionException;
    	//带超时时间的get()版本,如果阻塞等待过程中超时则会抛出TimeoutException异常。
    	V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
    }
    

四、通过线程池创建线程

仍然利用上一个方法中定义好的 MyCallable 类。
该方式有返回值,可以获取线程返回值,方式如下:

public class MyThreadPool {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future<String> f = executorService.submit(new MyCallable("My Callable 1"));
        if (!f.isDone()){
            System.out.println("thread task is not finished, plase wait");
        }
        System.out.println("Thread Return:"+f.get());
    }
}

输出结果:

thread task is not finished, plase wait
Current Thread Param:My Callable 1,Current Thread Name:pool-1-thread-1
Thread Return:My Callable 1 is executed

总结:
首先了解一下Executor的继承关系图:
Executor的继承关系图
ExecutorService、Callable 都是属于 Executor。Executor框架是Java 5中引入的,其内部使用了线程池机制,它在 java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。

  • Executor:一个接口,其定义了一个接收 Runnable 对象的方法 execute。一般来说,Runnable 任务开辟在新线程中的使用方法为:new Thread(new RunnableTask())).start(),但在 Executor 中,可以使用 Executor 而不用显示地创建线程:executor.execute(new RunnableTask());
  • ExecutorService:是 Executor 的子类接口,其提供了生命周期管理的方法,返回 Future 对象,以及可跟踪一个或多个异步任务执行状况返回Future的方法;可以调用 ExecutorService 的 shutdown() 方法来平滑地关闭 ExecutorService,调用该方法后,将导致ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后将会关闭ExecutorService。因此一般用该接口来实现和管理多线程。
  • Executors:提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口(返回的线程池继承了 AbstractExecutorService 抽象类,而该抽象类实现了 ExecutorService 接口)。
    • newFixedThreadPool:创建固定数目线程的线程池
    • newCachedThreadPool:创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
    • newScheduledThreadPool:创建一个支持定时及周期性的任务执行的线程池
    • newSingleThreadExecutor:创建一个单线程化的Executor

Executor VS ExecutorService VS Executors

  1. Executor 和 ExecutorService 这两个接口主要的区别是:ExecutorService 接口继承了 Executor 接口,是 Executor 的子接口。
  2. Executor 和 ExecutorService 第二个区别是:Executor 接口定义了 execute()方法用来接收一个 Runnable 接口的对象,而 ExecutorService 接口中的 submit()方法可以接受 Runnable 和 Callable 接口的对象。
  3. Executor 和 ExecutorService 接口第三个区别是 Executor 中的 execute() 方法不返回任何结果,而 ExecutorService 中的 submit()方法返回一个 Future 对象,可以通过这个 Future 对象返回线程结果。
  4. Executor 和 ExecutorService 接口第四个区别是 ExecutorService 还提供用来控制线程池的方法。比如:调用 shutDown() 方法终止线程池。
  5. Executors 类提供工厂方法用来创建不同类型的线程池。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值