JAVA实现多线程的方式有两种,继承Thread,实现Runnable,
但在JDK1.5之后又有一种新的方式:实现Callable<V>接口
package Test2016.demo; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Demo9 { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executors = Executors.newFixedThreadPool(5); long start = System.currentTimeMillis(); /** List<Future<Integer>> futures = new ArrayList<Future<Integer>>(10); for (int i = 1; i <= 10; i++) { futures.add(executors.submit(new MyTask1(i))); } for (Future<Integer> future : futures) { Integer result = future.get(); System.out.println("线程:" + result + "执行完毕!!!"); } */ CompletionService<Integer> completionServices = new ExecutorCompletionService<Integer>(executors); for (int i = 1; i <= 10; i++) { completionServices.submit(new MyTask1(i)); } for (int i = 1; i <= 10; i++) { Integer result = completionServices.take().get(); System.out.println("线程:" + result + "执行完毕!!!"); } long end = System.currentTimeMillis(); System.out.println("本次共历时:" + (end - start) / 1000 + "秒"); executors.shutdown(); //必须手动关闭线程池 } } class MyTask1 implements Callable<Integer> { private int taskNum; public MyTask1(int num) { this.taskNum = num; } @Override public Integer call() throws Exception { System.out.println("执行线程:" + taskNum); Thread.sleep(1000); return taskNum; } }
执行结果:
Future:
CompletionService:
使用Future接口获取任务的状态,按照的是线程的执行顺序来返回结果,即:先执行先获取结果
使用CompletionService接口来获取任务的状态,按照的是执行结束的顺序获取对应的结果,即:先结束先获取结果
EG:如果两个线程,线程1先执行,线程2后执行,但是线程1执行完需要100s,线程2执行完需要1s,
如果使用Future获取结果状态:
线程1 complete!!!
线程2 complete!!!
如果使用CompletionService获取结果状态:
线程2 complete!!!
线程1 complete!!!
附:ExecutorService接口(源码:public interface ExecutorService extends Executor{ })创建线程池方式:
ThreadPoolExecutor实现线程池 ThreadPoolExecutor类是ExecutorService接口的一个实现类 源码:public class ThreadPoolExecutor extends AbstractExecutorService { } public abstract class AbstractExecutorService implements ExecutorService { }
package Test2016.demo; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class Demo8 { public static void main(String[] args) { /** * corePoolSize : 线程池维护线程的最少数量 * maximumPoolSize : 线程池维护线程的最大数量 * keepAliveTime : 线程池维护线程所允许的空闲时间 * unit : 线程池维护线程所允许的空闲时间的单位 * workQueue : 线程池所使用的缓冲队列 * handler : 线程池对拒绝任务的处理策略 * */ ThreadPoolExecutor executor = new ThreadPoolExecutor(15, 50, 200, TimeUnit.NANOSECONDS, new ArrayBlockingQueue<Runnable>(15)); for (int i = 1; i <= 50; i++) { MyTask myTask = new MyTask(i); executor.execute(myTask); System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+ executor.getQueue().size()+",已执行完别的任务数目:"+executor.getCompletedTaskCount()); } executor.shutdown(); } } class MyTask implements Runnable { private int taskNum; public MyTask(int num) { this.taskNum = num; } @SuppressWarnings("static-access") public void run() { System.out.println("正在执行task:" + taskNum); try { Thread.currentThread().sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task "+taskNum+"执行完毕"); } }
1、corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。
在创建了线程池后,默认情况下,线程池中并没有任何线 程,而是等待有任务到来才创建线程去执行任务,
除非调用了prestartAllCoreThreads()或者 prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,
即在没有任务到来之前就创建 corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,
就会创建一个线程去执行任务,当线 程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
2、maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;
3、keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。
默认情况下,只有当线程池中的线程数大于corePoolSize 时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,
即当线程池中的线程数大于corePoolSize 时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。
但是如果调用了 allowCoreThreadTimeOut(boolean)方法,
在线程池中的线程数不大于corePoolSize 时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
4、unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
TimeUnit.DAYS; //天 TimeUnit.HOURS; //小时 TimeUnit.MINUTES; //分钟 TimeUnit.SECONDS; //秒 TimeUnit.MILLISECONDS; //毫秒 TimeUnit.MICROSECONDS; //微妙 TimeUnit.NANOSECONDS; //纳秒
5、workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,
一般来说,这里的阻塞队列有以下几种选择:
ArrayBlockingQueue; LinkedBlockingQueue; SynchronousQueue;
ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。
线程池的排队策略与BlockingQueue有关。
6、threadFactory:线程工厂,主要用来创建线程;
7、handler:表示当拒绝处理任务时的策略,有以下四种取值:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程) ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
参考博文:http://www.cnblogs.com/dolphin0520/p/3932921.html