Java多线程的四种实现方式

1.Java多线程实现的方式有四种:
1.继承Thread类,重写run方法
2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target
3.通过Callable和FutureTask创建线程
4.通过线程池创建线程
2.Thread实现方式
继承Thread类,重写run()方法,创建Thread对象调用start()方法启动线程。

public class ThreadDemo extends Thread {
    @Override
    public void run() {
        int t = 1;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "  " + (t++));
        }
    }

    public static void main(String[] args) {
        ThreadDemo td1 = new ThreadDemo();
        ThreadDemo td2 = new ThreadDemo();
        td1.setName("Thread1");
        td2.setName("Thread2");
        td1.start();
        td2.start();
    }
}

结果:

3.Runnable实现方式
实现Runnable接口,实现run()方法,接口的实现类的实例作为Thread的target传入带参的Thread构造函数,调用start()方法启动线程。

public class RunnableDemo implements Runnable {
    @Override
    public void run() {
        int t = 1;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "  " + (t++));
        }
    }

    public static void main(String[] args) {
        RunnableDemo rd = new RunnableDemo();
        Thread tr1 = new Thread(rd);
        Thread tr2 = new Thread(rd);
        tr1.setName("Thread1");
        tr2.setName("Thread2");
        tr1.start();
        tr2.start();
    }
}
}

结果:

3.Callable和FutureTask创建线程实现方式
(1)创建Callable接口的实现类 ,并实现Call方法;
(2)创建Callable实现类的实现,使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的Call方法的返回值 ;
(3)使用FutureTask对象作为Thread对象的target创建并启动线程;
(4)调用FutureTask对象的get()来获取子线程执行结束的返回值。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableFutureTaskDemo implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int t = 1;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "  " + (t++));
        }
        return t;
    }

    public static void main(String[] args) {
        Callable<Integer> cftd1 = new CallableFutureTaskDemo();
        Callable<Integer> cftd2 = new CallableFutureTaskDemo();
        FutureTask<Integer> ft1 = new FutureTask<>(cftd1);
        FutureTask<Integer> ft2 = new FutureTask<>(cftd2);
        Thread t1 = new Thread(ft1);
        Thread t2 = new Thread(ft2);
        t1.setName("Thread1");
        t2.setName("Thread2");
        t1.start();
        t2.start();
        try {
            System.out.println(ft1.get());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

结果:

5.线程池实现方式

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorDemo implements Runnable {
    private static int task_num = 2;  //任务数量

    @Override
    public void run() {
        int t = 1;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "  " + (t++));
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i <task_num; i++) {
            ExecutorDemo ed = new ExecutorDemo();
            executorService.execute(ed);
        }
        executorService.shutdown();
    }
}

结果:

java里面的线程池的顶级接口是Executor,Executor并不是一个线程池,而只是一个执行线程的工具,而真正的线程池是ExecutorService。
java中的有哪些线程池?
1.newCachedThreadPool创建一个可缓存线程池程
2.newFixedThreadPool 创建一个定长线程池
3.newScheduledThreadPool 创建一个定长线程池
4.newSingleThreadExecutor 创建一个单线程化的线程池
这里的例子用到的就是newFixedThreadPool 。

6.总结
(1)实现Runnable接口比继承Thread类更具有优势!Runnable接口适合多个相同的程序代码的线程去处理同一个资源,可以避免java中的单继承的限制,增加程序的健壮性,而且代码可以被多个线程共享,实现代码和数据独立。

(2)使用线程池可以减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务,可以根据系统的承受能力,调整线程池中工作线线程的数量。

(3)实际应用中,可以通过一个boolean标志位来结束线程。

(4)ExecutorService、Callable都是属于Executor框架。返回结果的线程是在JDK1.5中引入的新特征,还有Future接口也是属于这个框架,有了这种特征得到返回值更方便。
执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的值(由泛型决定)了。get()方法是阻塞的,即线程无返回结果,get方法会一直等待。此外,ExecutoreService提供了submit()方法,传递一个Callable或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。

原文地址:https://www.cnblogs.com/ericz2j/p/10281572.html