利用java的多线程编程可以大大的提高系统的并发运行效率,线程越多并发执行的任务就越多,但是并不意味着效率会一直提高,相反会得到适得其反的效果。
java中的多线程编程一共有三种方法:
继承Thread类
继承Runnable接口
使用线程池Executor
下面简单的介绍一些Executor的使用
一、话不多说先上代码:
创建一个线程数为3的线程池,模拟十个任务让线程池调度线程去完成。
1 package executorExample; 2 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 6 public class Threads{ 7 private static final int nThreads = 3; 8 private int i; 9 public void Thread(){ 10 //实现ExecutorService接口创建 线程数为三个的线程池 11 ExecutorService executorService = Executors.newFixedThreadPool(nThreads); 12 for (i = 0; i < 10; i++) { 13 //在匿名内部类中变量index还在必须把index声明成final类型 14 final int index = i; 15 executorService.execute(new Runnable() { 16 @Override 17 public void run() { 18 // TODO Auto-generated method stub 19 String threadName = Thread.currentThread().getName();//获取当前线程的名字 20 System.out.println(threadName+"正在执行任务:"+index); 21 } 22 }); 23 } 24 } 25 public static void main(String[] args){ 26 Threads thread = new Threads(); 27 thread.Thread(); 28 } 29 }
接下来解释一下这段代码。在这段代码当中用到的关键词有ExcutorService,Executors,newFixedThreadPool和execute方法,还有一个最重要的Executor,现在来解释一下他们之间的关系
1、Executors
首先我们先看一下Executors的源码
1 public static ExecutorService newFixedThreadPool(int nThreads) { 2 return new ThreadPoolExecutor(nThreads, nThreads, 3 0L, TimeUnit.MILLISECONDS, 4 new LinkedBlockingQueue<Runnable>()); 5 } 6 public static ExecutorService newWorkStealingPool(int parallelism) { 7 return new ForkJoinPool 8 (parallelism, 9 ForkJoinPool.defaultForkJoinWorkerThreadFactory, 10 null, true); 11 } 12 public static ExecutorService newWorkStealingPool() { 13 return new ForkJoinPool 14 (Runtime.getRuntime().availableProcessors(), 15 ForkJoinPool.defaultForkJoinWorkerThreadFactory, 16 null, true); 17 } 18 public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { 19 return new ThreadPoolExecutor(nThreads, nThreads, 20 0L, TimeUnit.MILLISECONDS, 21 new LinkedBlockingQueue<Runnable>(), 22 threadFactory); 23 }
1 public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { 2 return new FinalizableDelegatedExecutorService 3 (new ThreadPoolExecutor(1, 1, 4 0L, TimeUnit.MILLISECONDS, 5 new LinkedBlockingQueue<Runnable>(), 6 threadFactory)); 7 } 8 public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { 9 return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 10 60L, TimeUnit.SECONDS, 11 new SynchronousQueue<Runnable>(), 12 threadFactory); 13 }
里面有四种都是ExecutorService类型的线程池,也就是说,我们在创建线程池的时候可以有四种选择,newCachedThreadPool,newFixedThreadPool,newSingleThreadExecutor,newWorkStealingPool。其中最常用的就是newCatchedThreadPool和newFixedThreadPool,可以看到每个线程池的参数队列是不同的,LinkedBlockingQueue<Runnable>()属于无边界队列,
(1)newFixedThreadPool
是一个固定线程数的线程池,当线程池里线程满了之后,下载任务就会被阻塞到等待下载队列里面等待下载。而LinkedBlockingQueue<Runnable>()无限扩容的FIFO规则的队列,我们在编程的时候一般用它比较多。
(2)newCatchedThreadPool
是一个可缓存线程池,如果线程池里的线程数超过了处理需要,则线程池可以灵活的回收空闲的线程,
别的线程池就先不介绍了
2、ExecutorService
1 public interface ExecutorService extends Executor {
在接口ExecutorService的源码中我们可以看到继承了Executor类,并且在ExecutorService方法中实现了
void shutdown(); invokeAll(); submit();
等等的方法。
3、Executor
1 public interface Executor { 2 3 void execute(Runnable command); 4 }
在接口Executor中只有一个execute()方法,这是用来将任务提交给线程的。
到这里就明白了他们之间的关系,这样可以帮助我们更好的利用线程池去提高我们的代码效率。
写的不是很完善,如果有大神,希望多多指教,写这个东西也是为了自己能够更熟练的使用线程池。