第一种:extend Threadjava
第二种:implement Runnable多线程
第三种:Executors.newFixedThreadPool(int n).execute(...)测试
第一种(继承)、第二种(实现接口)是所有版本jdk一直支持,第三种(线程池)jdk1.5才开始出现。this
/*第一种 1.自定义类继承Thread 2.自定义类复写run方法 3.实例化自定义类,调用start方法(做用是启动线程并调用复写的run方法) */ class Demo extend Thread{ public void run(){...} } class T{ public static void main(String[] args){ new Demo().start(); //线程1 new Demo().start(); //线程2 new Demo().start(); //线程3 } }
/*第二种【经常使用】 1.自定义类实现Runnable接口 2.自定义类复写run方法 3.实例化自定义类,把自定义类的实例做为参数实例化Thread类(可实例化多个,就是所谓的多线程),而后调用start方法 */ class Demo implement Runnable{ public void run(){...} } class T{ public static void main(String[] args){ Demo demo = new Demo(); new Thead(demo).start(); //线程1 new Thead(demo).start(); //线程2 new Thead(demo).start(); //线程3 } }
第一种和第二种方法其实同样,主要是由于java的单继承机制才出现了第二种【经常使用】方法。线程
//第三种 //简易版 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Test{ public static void main(String[] args){ ExecutorService pool = Executors.newFixedThreadPool(3); //建立线程池,容量为3 for(int i=0;i<10;i++) { pool.execute(new Runnable(){public void run(){ System.out.println();}}); } Executors.newCachedThreadPool().execute(new Runnable(){public void run(){}}); Executors.newSingleThreadExecutor().execute(new Runnable(){public void run(){}}); } } //详细版(可运行进行测试) import java.util.concurrent.*; import java.util.Date; import java.util.List; import java.util.ArrayList; public class Test { 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对象 //pool提交一个返回值的任务用于执行,返回一个表示任务的未决结果的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()) + "毫秒】"); } } //有返回值实现Callable,无返回值实现Runnable class MyCallable implements Callable<Object> { private String taskNum; MyCallable(String taskNum) { this.taskNum = taskNum; } //实现Callable必须实现call方法 //计算结果,若是没法计算结果,则抛出一个异常。 public Object call() throws Exception { System.out.println(">>>" + taskNum + "任务启动"); Date dateTmp1 = new Date(); Thread.sleep(1000); Date dateTmp2 = new Date(); long time = dateTmp2.getTime() - dateTmp1.getTime(); System.out.println(">>>" + taskNum + "任务终止"); return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】"; } }
个人理解:code
由Executors.newFixedThreadPool(int n)定义一个能够执行必定数量线程的线程池,pool.submit(c)把须要执行的任务扔进(提交到)线程池进行执行,这样就能够不阻塞得同时执行多个任务(即所谓的多线程)。对象
Callable和Runnable同样是接口,二者的区别是Callable执行完call()后返回一个Object,Runnable执行完run()后不返回。call()和run()功能相同(除了有无返回值的区别)。继承
Future是一个类型(也就是类啦),用来装Callable执行完call()后返回的Object(其实这里返回的是Object,为啥不能用Object来装,非要用Future来装呢?我也不明白,可是API说须要用这个装就用呗)。接口
因为是多线程,每一个线程都执行完都有返回,因此须要用一个容器(即集合)——ArrayList<Future>来装。队列
线程池的方法能够获取任务执行的返回值(这些返回值可能有用),另外,此方法也能够执行submit(T<? implement Runnable>)无返回值的方法。
so,我以为第三种通吃,直接用第三种方式得了。