JAVA 多线程 三种 实现方式

转载参考 https://www.cnblogs.com/yezhenhan/archive/2012/01/09/2317636.html

JAVA 多线程实现方式有三种

  1、 继承 Thread类

  2、实现 Runaable 接口

  3、使用 ExecutorService、Callable、Future 实现有返回结果的多线程。

前两种方式都是没有返回值,只有最后一种是带返回值的。

 

1、继承 Thread 类实现多线程

  继承Thread 类的方法尽管被列为一种多线程的方式,但本质上也是实现了 Runnable 接口的一个实例,它代表一个线程的实例,并且,启动线程唯一的方法就是通过 Thread 类的 start() 实例方法。 start() 方法是一个 native 方法,他将启动一个新线程,并且 run() 方法。 这种方式实现多线程很简单,通过自己的类直接 extend Thread , 并 复写 run() 方法,就可以启动新线程并执行自己定义的 run() 方法。 例如:

public class ThreadDemo extends Thread{

    public void run() {
        System.out.println("Thread run");
    }

    public static void main(String[] args) throws Exception{
        ThreadDemo threadDemo = new ThreadDemo();
        ThreadDemo threadDemo1 = new ThreadDemo();

        threadDemo.start();
        threadDemo1.start();
    }
}

2、 实现Runnable 接口实现多线程

如果自己的类已经 extends 另一个类,就无法再 extends Thread 类,此时,需要实现 Runnable 接口, 例如:

public class RunnableDemo extends ThreadDemo implements Runnable {

    public void run() {
        System.out.println("Runnable run");
    }

    public static void main(String[] args) throws Exception{
        RunnableDemo runnableDemo = new RunnableDemo();

        Thread thread = new Thread(runnableDemo);
        thread.start();
    }

}

3、 使用 ExecutorService、 Callable、 Future 实现有返回结果的多线程

ExecutorService、Callable、Future 这个对象实际上都是属于 Executor 框架中的功能类。返回结果的线程是在 JDK1.5 中引入的新特征。

可返回值的任务必须实现 Callable 接口,类似的,无返回值的任务必须实现 Runnable 接口。 执行 Callable 任务后,可以获取一个 Future 的对象,在该对象上调用 get 就可以获取到 Callable 任务返回到 Object了,再结合线程池接口 ExecutorService 就可以实现传说中有返回结果的多线程了。示例如下:

public class CallableDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("---------------程序开始执行-------------");
        Date date1 = new Date();

        int taskSize = 5;
        //创建一个线程池
        ExecutorService pool = Executors.newFixedThreadPool(taskSize);
        // 创建多个有返回值的任务
        List<Future> list = new ArrayList<Future>();
        for(int i=0; i<taskSize; i++) {
            Callable c = new MyCallable(i + " ");
            // 执行任务并获取 Future 对象
            Future f = pool.submit(c);
//            System.out.println("返回结果 >>>" + f.get().toString());
            list.add(f);
        }
        pool.shutdown();

        //获取所有并发任务的运行结果
        for(Future f : list) {
            System.out.println(">>>" + f.get().toString());
        }

        Date date2 = new Date();
        System.out.println("-----------程序结束运行--------,程序运行时间【"
                + (date2.getTime() - date1.getTime()) + "毫秒】");
    }

    static class MyCallable implements Callable<Object> {

        private String taskNum;

        MyCallable(String taskNum) {
            this.taskNum = taskNum;
        }

        @Override
        public Object call() throws Exception {
            System.out.println(">>>" + taskNum + "任务启动");
            Date dateTmp1 = new Date();
            Thread.sleep(3000);
            Date dateTmp2 = new Date();
            long time = dateTmp2.getTime() - dateTmp1.getTime();
            System.out.println(">>>" + taskNum + "任务终止");
            return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
        }
    }

代码说明:

上述代码中 Executors 类, 提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService 接口。源码中

//创建固定数目线程的线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
// 创建一个可缓存的线程池,调用 execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。中止并从缓存中移除那些已有60秒中未被使用的线程
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
//创建一个单线程化的 Executor
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }
//创建一个支持定时及周期行的任务执行的线程池,多数情况下可用来替代 Timer 类
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

ExecutorService 提供了 submit() 方法,传递一个Callable,或 Runnable, 返回Future. 如果Executor 后台线程池还没有完成Callabled 计算,这调用返回 Future 对象的 get() 方法,会阻塞直到计算完成。

 

posted @ 2022-02-15 11:36  长弓射大狗  阅读(351)  评论(0编辑  收藏  举报